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

lua_config.c 101KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128
  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 "lua_common.h"
  17. #include "libmime/message.h"
  18. #include "libutil/expression.h"
  19. #include "libserver/composites.h"
  20. #include "libserver/cfg_file_private.h"
  21. #include "libmime/lang_detection.h"
  22. #include "lua/lua_map.h"
  23. #include "lua/lua_thread_pool.h"
  24. #include "utlist.h"
  25. #include <math.h>
  26. /***
  27. * This module is used to configure rspamd and is normally available as global
  28. * variable named `rspamd_config`. Unlike other modules, it is not necessary to
  29. * require it before usage.
  30. * @module rspamd_config
  31. * @example
  32. -- Register some callback symbol
  33. local function foo(task)
  34. -- do something
  35. end
  36. rspamd_config:register_symbol('SYMBOL', 1.0, foo)
  37. -- Get configuration
  38. local tab = rspamd_config:get_all_opt('module') -- get table for module's options
  39. local opts = rspamd_config:get_key('options') -- get content of the specified key in rspamd configuration
  40. */
  41. /* Config file methods */
  42. /***
  43. * @method rspamd_config:get_module_opt(mname, optname)
  44. * Returns value of specified option `optname` for a module `mname`,
  45. * @param {string} mname name of module
  46. * @param {string} optname option to get
  47. * @return {string or table} value of the option or `nil` if option is not found
  48. */
  49. LUA_FUNCTION_DEF (config, get_module_opt);
  50. /***
  51. * @method rspamd_config:get_all_opt(mname)
  52. * Returns value of all options for a module `mname`, flattening values into a single table consisting
  53. * of all sections with such a name.
  54. * @param {string} mname name of module
  55. * @return {table} table of all options for `mname` or `nil` if a module's configuration is not found
  56. */
  57. LUA_FUNCTION_DEF (config, get_all_opt);
  58. /***
  59. * @method rspamd_config:get_ucl()
  60. * Returns full configuration as a native Lua object (ucl to lua conversion).
  61. * This method uses caching if possible.
  62. * @return {table} table of all options in the configuration
  63. */
  64. LUA_FUNCTION_DEF (config, get_ucl);
  65. /***
  66. * @method rspamd_config:get_mempool()
  67. * Returns static configuration memory pool.
  68. * @return {mempool} [memory pool](mempool.md) object
  69. */
  70. LUA_FUNCTION_DEF (config, get_mempool);
  71. /***
  72. * @method rspamd_config:get_resolver()
  73. * Returns DNS resolver.
  74. * @return {dns_resolver} opaque DNS resolver pointer if any
  75. */
  76. LUA_FUNCTION_DEF (config, get_resolver);
  77. /***
  78. * @method rspamd_config:add_radix_map(mapline[, description])
  79. * Creates new dynamic map of IP/mask addresses.
  80. * @param {string} mapline URL for a map
  81. * @param {string} description optional map description
  82. * @return {map} radix tree object
  83. * @example
  84. local ip_map = rspamd_config:add_radix_map ('file:///path/to/file', 'my radix map')
  85. ...
  86. local function foo(task)
  87. local ip = task:get_from_ip()
  88. if ip_map:get_key(ip) then
  89. return true
  90. end
  91. return false
  92. end
  93. */
  94. /***
  95. * @method rspamd_config:radix_from_config(mname, optname)
  96. * Creates new embedded map of IP/mask addresses from config.
  97. * @param {string} mname name of module
  98. * @param {string} optname option to get
  99. * @return {map} radix tree object
  100. * @example
  101. local ip_map = rspamd_config:radix_from_config ('mymodule', 'ips')
  102. ...
  103. local function foo(task)
  104. local ip = task:get_from_ip()
  105. if ip_map:get_key(ip) then
  106. return true
  107. end
  108. return false
  109. end
  110. */
  111. /***
  112. * @method rspamd_config:radix_from_ucl(obj)
  113. * Creates new embedded map of IP/mask addresses from object.
  114. * @param {ucl} obj object
  115. * @return {map} radix tree object
  116. */
  117. /***
  118. * @method rspamd_config:add_hash_map(mapline[, description])
  119. * Creates new dynamic map string objects.
  120. * @param {string} mapline URL for a map
  121. * @param {string} description optional map description
  122. * @return {map} hash set object
  123. * @example
  124. local hash_map = rspamd_config:add_hash_map ('file:///path/to/file', 'my hash map')
  125. ...
  126. local function foo(task)
  127. local from = task:get_from()
  128. if hash_map:get_key(from['user']) then
  129. return true
  130. end
  131. return false
  132. end
  133. */
  134. /***
  135. * @method rspamd_config:add_kv_map(mapline[, description])
  136. * Creates new dynamic map of key/values associations.
  137. * @param {string} mapline URL for a map
  138. * @param {string} description optional map description
  139. * @return {map} hash table object
  140. * @example
  141. local kv_map = rspamd_config:add_kv_map ('file:///path/to/file', 'my kv map')
  142. ...
  143. local function foo(task)
  144. local from = task:get_from()
  145. if from then
  146. local value = kv_map:get_key(from['user'])
  147. if value then
  148. return true,value
  149. end
  150. end
  151. return false
  152. end
  153. */
  154. /***
  155. * @method rspamd_config:add_map({args})
  156. * Creates new dynamic map according to the attributes passed.
  157. *
  158. * - `type`: type of map to be created, can be one of the following set:
  159. * + `set`: set of strings
  160. * + `radix`: map of IP addresses to strings
  161. * + `map`: map of strings to strings
  162. * + `regexp`: map of regexps to strings
  163. * + `callback`: map processed by lua callback
  164. * - `url`: url to load map from
  165. * - `description`: map's description
  166. * - `callback`: lua callback for the map
  167. *
  168. * @return {map} `true` if map has been added
  169. * @example
  170. local str = ''
  171. local function process_map(in)
  172. str = in
  173. end
  174. rspamd_config:add_map('http://example.com/map', "settings map", process_map)
  175. */
  176. /***
  177. * @method rspamd_config:get_maps()
  178. * Get all maps defined as an array of rspamd{map} objects
  179. *
  180. * @return {table|rspamd{map}}
  181. */
  182. /***
  183. * @method rspamd_config:get_classifier(name)
  184. * Returns classifier config.
  185. * @param {string} name name of classifier (e.g. `bayes`)
  186. * @return {classifier} classifier object or `nil`
  187. */
  188. LUA_FUNCTION_DEF (config, get_classifier);
  189. /***
  190. * @method rspamd_config:register_symbol(table)
  191. * Register symbol of a specified type in rspamd. This function accepts table of arguments:
  192. *
  193. * - `name`: name of symbol (can be missing for callback symbols)
  194. * - `callback`: function to be called for symbol's check (can be absent for virtual symbols)
  195. * - `weight`: weight of symbol (should normally be 1 or missing)
  196. * - `priority`: priority of symbol (normally 0 or missing)
  197. * - `type`: type of symbol: `normal` (default), `virtual` or `callback`
  198. * - `flags`: various flags split by commas or spaces:
  199. * + `nice` if symbol can produce negative score;
  200. * + `empty` if symbol can be called for empty messages
  201. * + `skip` if symbol should be skipped now
  202. * + `nostat` if symbol should be excluded from stat tokens
  203. * + `trivial` symbol is trivial (e.g. no network requests)
  204. * + `explicit_disable` requires explicit disabling (e.g. via settings)
  205. * + `ignore_passthrough` executed even if passthrough result has been set
  206. * - `parent`: id of parent symbol (useful for virtual symbols)
  207. *
  208. * @return {number} id of symbol registered
  209. */
  210. LUA_FUNCTION_DEF (config, register_symbol);
  211. /***
  212. * @method rspamd_config:register_symbols(callback, [weight], callback_name, [, symbol, ...])
  213. * Register callback function to be called for a set of symbols with initial weight.
  214. * @param {function} callback callback function to be called for a specified symbol
  215. * @param {number} weight initial weight of symbol (can be less than zero to specify non-spam symbols)
  216. * @param {string} callback_name symbolic name of callback
  217. * @param {list of strings} symbol list of symbols registered by this function
  218. */
  219. LUA_FUNCTION_DEF (config, register_symbols);
  220. /***
  221. * @method rspamd_config:register_virtual_symbol(name, weight,)
  222. * Register virtual symbol that is not associated with any callback.
  223. *
  224. * **This method is deprecated and should not be used in newly written code **
  225. * @param {string} virtual name symbol's name
  226. * @param {number} weight initial weight of symbol (can be less than zero to specify non-spam symbols)
  227. */
  228. LUA_FUNCTION_DEF (config, register_virtual_symbol);
  229. /***
  230. * @method rspamd_config:register_callback_symbol(name, weight, callback)
  231. * Register callback function to be called for a specified symbol with initial weight. Symbol itself is
  232. * not registered in the metric and is not intended to be visible by a user.
  233. *
  234. * **This method is deprecated and should not be used in newly written code **
  235. * @param {string} name symbol's name (just for unique id purposes)
  236. * @param {number} weight initial weight of symbol (can be less than zero to specify non-spam symbols)
  237. * @param {function} callback callback function to be called for a specified symbol
  238. */
  239. LUA_FUNCTION_DEF (config, register_callback_symbol);
  240. LUA_FUNCTION_DEF (config, register_callback_symbol_priority);
  241. /***
  242. * @method rspamd_config:register_dependency(id, dep)
  243. * Create a dependency between symbol identified by `id` and a symbol identified
  244. * by some symbolic name `dep`
  245. * @param {number|string} id id or name of source (numeric id is returned by all register_*_symbol)
  246. * @param {string} dep dependency name
  247. * @example
  248. local function cb(task)
  249. ...
  250. end
  251. local id = rspamd_config:register_symbol('SYM', 1.0, cb)
  252. rspamd_config:register_dependency(id, 'OTHER_SYM')
  253. -- Alternative form
  254. rspamd_config:register_dependency('SYMBOL_FROM', 'SYMBOL_TO')
  255. */
  256. LUA_FUNCTION_DEF (config, register_dependency);
  257. /***
  258. * @method rspamd_config:get_symbol_flags(name)
  259. * Returns symbol flags
  260. * @param {string} name symbols's name
  261. * @return {table|string} list of flags for symbol or nil
  262. */
  263. LUA_FUNCTION_DEF (config, get_symbol_flags);
  264. /***
  265. * @method rspamd_config:add_symbol_flags(name, flags)
  266. * Adds flags to a symbol
  267. * @param {string} name symbols's name
  268. * @param {table|string} flags flags to add
  269. * @return {table|string} new set of flags
  270. */
  271. LUA_FUNCTION_DEF (config, add_symbol_flags);
  272. /**
  273. * @method rspamd_config:register_re_selector(name, selector_str)
  274. * Registers selector with the specific name to use in regular expressions in form
  275. * name=/re/$ or name=/re/{selector}
  276. * @param {string} name name of the selector
  277. * @param {selector_str} selector string
  278. * @return true if selector has been registered
  279. */
  280. LUA_FUNCTION_DEF (config, register_re_selector);
  281. /**
  282. * @method rspamd_config:set_symbol({table})
  283. * Sets the value of a specified symbol in a metric. This function accepts table with the following elements:
  284. *
  285. * - `name`: name of symbol (string)
  286. * - `score`: score for symbol (number)
  287. * - `metric`: name of metric (string, optional)
  288. * - `description`: description of symbol (string, optional)
  289. * - `group`: name of group for symbol (string, optional)
  290. * - `one_shot`: turn off multiple hits for a symbol (boolean, optional)
  291. * - `one_param`: turn off multiple options for a symbol (boolean, optional)
  292. * - `flags`: comma separated string of flags:
  293. * + `ignore`: do not strictly check validity of symbol and corresponding rule
  294. * + `one_shot`: turn off multiple hits for a symbol
  295. * + `one_param`: allow only one parameter for a symbol
  296. * - `priority`: priority of symbol's definition
  297. */
  298. LUA_FUNCTION_DEF (config, set_metric_symbol);
  299. /**
  300. * @method rspamd_config:set_action({table})
  301. * Sets the score of a specified action in a metric. This function accepts table with the following elements:
  302. *
  303. * - `action`: name of action (string)
  304. * - `score`: score for action (number)
  305. * - `metric`: name of metric (string, optional)
  306. * - `priority`: priority of action's definition
  307. */
  308. LUA_FUNCTION_DEF (config, set_metric_action);
  309. /**
  310. * @method rspamd_config:get_symbol(name)
  311. * Gets metric data for a specific symbol identified by `name`:
  312. *
  313. * - `score`: score for symbol (number)
  314. * - `description`: description of symbol (string, optional)
  315. * - `group`: name of group for symbol (string, optional)
  316. * - `one_shot`: turn off multiple hits for a symbol (boolean, optional)
  317. * - `flags`: comma separated string of flags:
  318. * + `ignore`: do not strictly check validity of symbol and corresponding rule
  319. * + `one_shot`: turn off multiple hits for a symbol
  320. *
  321. * @param {string} name name of symbol
  322. * @return {table} symbol's definition or nil in case of undefined symbol
  323. */
  324. LUA_FUNCTION_DEF (config, get_metric_symbol);
  325. /**
  326. * @method rspamd_config:get_action(name)
  327. * Gets data for a specific action in config. This function returns number reperesenting action's score
  328. *
  329. * @param {string} name name of action
  330. * @return {number} action's score or nil in case of undefined score or action
  331. */
  332. LUA_FUNCTION_DEF (config, get_metric_action);
  333. /**
  334. * @method rspamd_config:get_all_actions()
  335. * Gets data for all action in config
  336. * @return {table|str->num} action's score or nil in case of undefined score or action
  337. */
  338. LUA_FUNCTION_DEF (config, get_all_actions);
  339. /**
  340. * @method rspamd_config:add_composite(name, expression)
  341. * @param {string} name name of composite symbol
  342. * @param {string} expression symbolic expression of the composite rule
  343. * @return {bool} true if a composite has been added successfully
  344. */
  345. LUA_FUNCTION_DEF (config, add_composite);
  346. /***
  347. * @method rspamd_config:register_pre_filter(callback[, order])
  348. * Register function to be called prior to symbols processing.
  349. * @param {function} callback callback function
  350. * @param {number} order filters are called from lower orders to higher orders, order is equal to 0 by default
  351. * @example
  352. local function check_function(task)
  353. -- It is possible to manipulate the task object here: set settings, set pre-action and so on
  354. ...
  355. end
  356. rspamd_config:register_pre_filter(check_function)
  357. */
  358. LUA_FUNCTION_DEF (config, register_pre_filter);
  359. /***
  360. * @method rspamd_config:register_post_filter(callback[, order])
  361. * Register function to be called after symbols are processed.
  362. *
  363. * @param {function} callback callback function
  364. * @param {number} order filters are called from lower orders to higher orders, order is equal to 0 by default
  365. */
  366. LUA_FUNCTION_DEF (config, register_post_filter);
  367. /* XXX: obsoleted */
  368. LUA_FUNCTION_DEF (config, register_module_option);
  369. /* XXX: not needed now */
  370. LUA_FUNCTION_DEF (config, get_api_version);
  371. /***
  372. * @method rspamd_config:get_key(name)
  373. * Returns configuration section with the specified `name`.
  374. * @param {string} name name of config section
  375. * @return {variant} specific value of section
  376. * @example
  377. local set_section = rspamd_config:get_key("settings")
  378. if type(set_section) == "string" then
  379. -- Just a map of ucl
  380. if rspamd_config:add_map(set_section, "settings map", process_settings_map) then
  381. rspamd_config:register_pre_filter(check_settings)
  382. end
  383. elseif type(set_section) == "table" then
  384. if process_settings_table(set_section) then
  385. rspamd_config:register_pre_filter(check_settings)
  386. end
  387. end
  388. */
  389. LUA_FUNCTION_DEF (config, get_key);
  390. /***
  391. * @method rspamd_config:add_condition(symbol, condition)
  392. * Adds condition callback for specified symbol
  393. * @param {string} symbol symbol's name
  394. * @param {function} condition condition callback
  395. * @return {boolean} true if condition has been added
  396. * @example
  397. rspamd_config:add_condition('FUZZY_DENIED', function(task)
  398. if some_map:find_key(task:get_from()) then return false end
  399. return true
  400. end)
  401. */
  402. LUA_FUNCTION_DEF (config, add_condition);
  403. /***
  404. * @method rspamd_config:enable_symbol(symbol)
  405. * Enables execution for the specified symbol
  406. * @param {string} symbol symbol's name
  407. */
  408. LUA_FUNCTION_DEF (config, enable_symbol);
  409. /***
  410. * @method rspamd_config:disable_symbol(symbol)
  411. * Disables execution for the specified symbol
  412. * @param {string} symbol symbol's name
  413. */
  414. LUA_FUNCTION_DEF (config, disable_symbol);
  415. /***
  416. * @method rspamd_config:__newindex(name, callback)
  417. * This metamethod is called if new indicies are added to the `rspamd_config` object.
  418. * Technically, it is the equivalent of @see rspamd_config:register_symbol where `weight` is 1.0.
  419. * There is also table form invocation that allows to control more things:
  420. *
  421. * - `callback`: has the same meaning and acts as function of task
  422. * - `score`: default score for a symbol
  423. * - `group`: default group for a symbol
  424. * - `description`: default symbol's description
  425. * - `priority`: additional priority value
  426. * - `one_shot`: default value for one shot attribute
  427. * - `condition`: function of task that can enable or disable this specific rule's execution
  428. * @param {string} name index name
  429. * @param {function/table} callback callback to be called
  430. * @return {number} id of the new symbol added
  431. * @example
  432. rspamd_config.R_EMPTY_IMAGE = function (task)
  433. parts = task:get_text_parts()
  434. if parts then
  435. for _,part in ipairs(parts) do
  436. if part:is_empty() then
  437. images = task:get_images()
  438. if images then
  439. -- Symbol `R_EMPTY_IMAGE` is inserted
  440. return true
  441. end
  442. return false
  443. end
  444. end
  445. end
  446. return false
  447. end
  448. rspamd_config.SYMBOL = {
  449. callback = function(task)
  450. ...
  451. end,
  452. score = 5.1,
  453. description = 'sample symbol',
  454. group = 'sample symbols',
  455. condition = function(task)
  456. if task:get_from()[1]['addr'] == 'user@example.com' then
  457. return false
  458. end
  459. return true
  460. end
  461. }
  462. */
  463. LUA_FUNCTION_DEF (config, newindex);
  464. /***
  465. * @method rspamd_config:register_regexp(params)
  466. * Registers new re for further cached usage
  467. * Params is the table with the following fields (mandatory fields are marked with `*`):
  468. * - `re`* : regular expression object
  469. * - `type`*: type of regular expression:
  470. * + `mime`: mime regexp
  471. * + `rawmime`: raw mime regexp
  472. * + `header`: header regexp
  473. * + `rawheader`: raw header expression
  474. * + `body`: raw body regexp
  475. * + `url`: url regexp
  476. * - `header`: for header and rawheader regexp means the name of header
  477. * - `pcre_only`: flag regexp as pcre only regexp
  478. */
  479. LUA_FUNCTION_DEF (config, register_regexp);
  480. /***
  481. * @method rspamd_config:replace_regexp(params)
  482. * Replaces regexp with a new one
  483. * Params is the table with the following fields (mandatory fields are marked with `*`):
  484. * - `old_re`* : old regular expression object (must be in the cache)
  485. * - `new_re`* : old regular expression object (must not be in the cache)
  486. */
  487. LUA_FUNCTION_DEF (config, replace_regexp);
  488. /***
  489. * @method rspamd_config:register_worker_script(worker_type, script)
  490. * Registers the following script for workers of a specified type. The exact type
  491. * of script function depends on worker type
  492. * @param {string} worker_type worker type (e.g. "normal")
  493. * @param {function} script script for a worker
  494. * @return {boolean} `true` if a script has been registered
  495. */
  496. LUA_FUNCTION_DEF (config, register_worker_script);
  497. /***
  498. * @method rspamd_config:add_on_load(function(cfg, ev_base, worker) ... end)
  499. * Registers the following script to be executed when configuration is completely loaded
  500. * @param {function} script function to be executed
  501. * @example
  502. rspamd_config:add_on_load(function(cfg, ev_base, worker)
  503. rspamd_config:add_periodic(ev_base, 1.0, function(cfg, ev_base)
  504. local logger = require "rspamd_logger"
  505. logger.infox(cfg, "periodic function in worker %s", worker:get_name())
  506. return true
  507. end)
  508. end)
  509. */
  510. LUA_FUNCTION_DEF (config, add_on_load);
  511. /***
  512. * @method rspamd_config:add_periodic(event_base, timeout, function(cfg, ev_base) ... end, [jitter = false])
  513. * Registers function to be periodically executed by Rspamd
  514. * @param {ev_base} event_base event base that is needed for async events
  515. * @param {number} timeout time in seconds (could be fractional)
  516. * @param {function} script function to be executed
  517. * @param {boolean} jitter `true` if timeout jittering is needed
  518. * @example
  519. rspamd_config:add_on_load(function(cfg, ev_base)
  520. rspamd_config:add_periodic(ev_base, 1.0, function(cfg, ev_base)
  521. local logger = require "rspamd_logger"
  522. logger.infox(cfg, "periodic function")
  523. return true -- if return false, then the periodic event is removed
  524. end)
  525. end)
  526. */
  527. LUA_FUNCTION_DEF (config, add_periodic);
  528. /***
  529. * @method rspamd_config:get_symbols_count()
  530. * Returns number of symbols registered in rspamd configuration
  531. * @return {number} number of symbols registered in the configuration
  532. */
  533. LUA_FUNCTION_DEF (config, get_symbols_count);
  534. /***
  535. * @method rspamd_config:get_symbols_cksum()
  536. * Returns checksum for all symbols in the cache
  537. * @return {int64} boxed value of the 64 bit checksum
  538. */
  539. LUA_FUNCTION_DEF (config, get_symbols_cksum);
  540. /***
  541. * @method rspamd_config:get_symbols_counters()
  542. * Returns table of all counters in the cache (weights, frequencies etc)
  543. * @return {table|tables} all symbols indexed by name
  544. */
  545. LUA_FUNCTION_DEF (config, get_symbols_counters);
  546. /***
  547. * @method rspamd_config:get_symbols_scores()
  548. * Returns table of all scores defined in config
  549. * @return {table|tables} all symbols indexed by name
  550. */
  551. LUA_FUNCTION_DEF (config, get_symbols_scores);
  552. /***
  553. * @method rspamd_config:get_symbol_callback(name)
  554. * Returns callback function for the specified symbol if it is a lua registered callback
  555. * @return {function} callback function or nil
  556. */
  557. LUA_FUNCTION_DEF (config, get_symbol_callback);
  558. /***
  559. * @method rspamd_config:get_symbol_stat(name)
  560. * Returns table with statistics for a specific symbol:
  561. * - `frequency`: frequency for symbol's hits
  562. * - `stddev`: standard deviation of `frequency`
  563. * - `time`: average time in seconds (floating point)
  564. * - `count`: total number of hits
  565. * @return {table} symbol stats
  566. */
  567. LUA_FUNCTION_DEF (config, get_symbol_stat);
  568. /***
  569. * @method rspamd_config:set_symbol_callback(name, callback)
  570. * Sets callback for the specified symbol
  571. * @return {boolean} true if function has been replaced
  572. */
  573. LUA_FUNCTION_DEF (config, set_symbol_callback);
  574. /***
  575. * @method rspamd_config:register_finish_script(callback)
  576. * Adds new callback that is called on worker process termination when all
  577. * tasks pending are processed
  578. *
  579. * @param callback {function} a function with one argument (rspamd_task)
  580. */
  581. LUA_FUNCTION_DEF (config, register_finish_script);
  582. /***
  583. * @method rspamd_config:register_monitored(url, type, [{params}])
  584. * Registers monitored resource to watch its availability. Supported types:
  585. *
  586. * - `dns`: DNS monitored object
  587. *
  588. * Params are optional table specific for each type. For DNS it supports the
  589. * following options:
  590. *
  591. * - `prefix`: prefix to add before making request
  592. * - `type`: type of request (e.g. 'a' or 'txt')
  593. * - `ipnet`: array of ip/networks to expect on reply
  594. * - `rcode`: expected return code (e.g. `nxdomain`)
  595. *
  596. * Returned object has the following methods:
  597. *
  598. * - `alive`: returns `true` if monitored resource is alive
  599. * - `offline`: returns number of seconds of the current offline period (or 0 if alive)
  600. * - `total_offline`: returns number of seconds of the overall offline
  601. * - `latency`: returns the current average latency in seconds (or 0 if offline)
  602. *
  603. * @param {string} url resource to monitor
  604. * @param {string} type type of monitoring
  605. * @param {table} opts optional parameters
  606. * @return {rspamd_monitored} rspamd monitored object
  607. */
  608. LUA_FUNCTION_DEF (config, register_monitored);
  609. /***
  610. * @method rspamd_config:add_doc(path, option, doc_string, [{params}])
  611. * Adds new documentation string for an option `option` at path `path`
  612. * Options defines optional params, such as:
  613. *
  614. * - `default`: default option value
  615. * - `type`: type of an option (`string`, `number`, `object`, `array` etc)
  616. * - `reqired`: if an option is required
  617. *
  618. * @param {string} path documentation path (e.g. module name)
  619. * @param {string} option name of the option
  620. * @param {string} doc_string documentation string
  621. * @param {table} params optional parameters
  622. */
  623. LUA_FUNCTION_DEF (config, add_doc);
  624. /***
  625. * @method rspamd_config:add_example(path, option, doc_string, example)
  626. * Adds new documentation
  627. *
  628. * @param {string} path documentation path (e.g. module name or nil for top)
  629. * @param {string} option name of the option
  630. * @param {string} doc_string documentation string
  631. * @param {string} example example in ucl format, comments are also parsed
  632. */
  633. LUA_FUNCTION_DEF (config, add_example);
  634. /***
  635. * @method rspamd_config:set_peak_cb(function)
  636. * Sets a function that will be called when frequency of some symbol goes out of
  637. * stddev * 2 over the last period of refreshment.
  638. *
  639. * @example
  640. rspamd_config:set_peak_cb(function(ev_base, sym, mean, stddev, value, error)
  641. -- ev_base: event base for async events (e.g. redis)
  642. -- sym: symbol's name
  643. -- mean: mean frequency value
  644. -- stddev: standard deviation of frequency
  645. -- value: current frequency value
  646. -- error: squared error
  647. local logger = require "rspamd_logger"
  648. logger.infox(rspamd_config, "symbol %s has changed frequency significantly: %s(%s) over %s(%s)",
  649. sym, value, error, mean, stddev)
  650. end)
  651. */
  652. LUA_FUNCTION_DEF (config, set_peak_cb);
  653. /***
  654. * @method rspamd_config:get_cpu_flags()
  655. * Returns architecture dependent flags supported by the CPU
  656. * Currently, only x86 flags are supported:
  657. * - 'ssse3'
  658. * - 'sse42'
  659. * - 'avx'
  660. * - 'avx2'
  661. * @return {table} flag -> true table
  662. */
  663. LUA_FUNCTION_DEF (config, get_cpu_flags);
  664. /***
  665. * @method rspamd_config:has_torch()
  666. * Returns true if Rspamd is compiled with torch support and the runtime CPU
  667. * supports sse4.2 required for torch.
  668. * @return {boolean} true if torch is compiled and supported
  669. */
  670. LUA_FUNCTION_DEF (config, has_torch);
  671. /***
  672. * @method rspamd_config:experimental_enabled()
  673. * Returns true if experimental plugins are enabled
  674. * @return {boolean} true if experimental plugins are enabled
  675. */
  676. LUA_FUNCTION_DEF (config, experimental_enabled);
  677. /***
  678. * @method rspamd_config:load_ucl(filename[, include_trace])
  679. * Loads config from the UCL file (but does not perform parsing using rcl)
  680. * @param {string} filename file to load
  681. * @return true or false + error message
  682. */
  683. LUA_FUNCTION_DEF (config, load_ucl);
  684. /***
  685. * @method rspamd_config:parse_rcl([skip_sections])
  686. * Parses RCL using loaded ucl file
  687. * @param {table|string} sections to skip
  688. * @return true or false + error message
  689. */
  690. LUA_FUNCTION_DEF (config, parse_rcl);
  691. /***
  692. * @method rspamd_config:init_modules()
  693. * Initialize lua and internal modules
  694. * @return true or false
  695. */
  696. LUA_FUNCTION_DEF (config, init_modules);
  697. /***
  698. * @method rspamd_config:init_subsystem(str)
  699. * Initialize config subsystem from a comma separated list:
  700. * - `modules` - init modules
  701. * - `langdet` - language detector
  702. * - `dns` - DNS resolver
  703. * - TODO: add more
  704. */
  705. LUA_FUNCTION_DEF (config, init_subsystem);
  706. /***
  707. * @method rspamd_config:get_tld_path()
  708. * Returns path to TLD file
  709. * @return {string} path to tld file
  710. */
  711. LUA_FUNCTION_DEF (config, get_tld_path);
  712. static const struct luaL_reg configlib_m[] = {
  713. LUA_INTERFACE_DEF (config, get_module_opt),
  714. LUA_INTERFACE_DEF (config, get_mempool),
  715. LUA_INTERFACE_DEF (config, get_resolver),
  716. LUA_INTERFACE_DEF (config, get_all_opt),
  717. LUA_INTERFACE_DEF (config, get_ucl),
  718. LUA_INTERFACE_DEF (config, add_radix_map),
  719. LUA_INTERFACE_DEF (config, radix_from_config),
  720. LUA_INTERFACE_DEF (config, radix_from_ucl),
  721. LUA_INTERFACE_DEF (config, add_hash_map),
  722. LUA_INTERFACE_DEF (config, add_kv_map),
  723. LUA_INTERFACE_DEF (config, add_map),
  724. LUA_INTERFACE_DEF (config, get_maps),
  725. LUA_INTERFACE_DEF (config, get_classifier),
  726. LUA_INTERFACE_DEF (config, register_symbol),
  727. LUA_INTERFACE_DEF (config, register_symbols),
  728. LUA_INTERFACE_DEF (config, register_virtual_symbol),
  729. LUA_INTERFACE_DEF (config, register_callback_symbol),
  730. LUA_INTERFACE_DEF (config, register_callback_symbol_priority),
  731. LUA_INTERFACE_DEF (config, register_dependency),
  732. LUA_INTERFACE_DEF (config, get_symbol_flags),
  733. LUA_INTERFACE_DEF (config, add_symbol_flags),
  734. LUA_INTERFACE_DEF (config, set_metric_symbol),
  735. {"set_symbol", lua_config_set_metric_symbol},
  736. LUA_INTERFACE_DEF (config, set_metric_action),
  737. {"set_action", lua_config_set_metric_action},
  738. LUA_INTERFACE_DEF (config, get_metric_symbol),
  739. {"get_symbol", lua_config_get_metric_symbol},
  740. LUA_INTERFACE_DEF (config, get_metric_action),
  741. {"get_action", lua_config_get_metric_action},
  742. LUA_INTERFACE_DEF (config, get_all_actions),
  743. LUA_INTERFACE_DEF (config, add_composite),
  744. LUA_INTERFACE_DEF (config, register_module_option),
  745. LUA_INTERFACE_DEF (config, register_pre_filter),
  746. LUA_INTERFACE_DEF (config, register_post_filter),
  747. LUA_INTERFACE_DEF (config, get_api_version),
  748. LUA_INTERFACE_DEF (config, get_key),
  749. LUA_INTERFACE_DEF (config, add_condition),
  750. LUA_INTERFACE_DEF (config, enable_symbol),
  751. LUA_INTERFACE_DEF (config, disable_symbol),
  752. LUA_INTERFACE_DEF (config, register_regexp),
  753. LUA_INTERFACE_DEF (config, replace_regexp),
  754. LUA_INTERFACE_DEF (config, register_worker_script),
  755. LUA_INTERFACE_DEF (config, register_re_selector),
  756. LUA_INTERFACE_DEF (config, add_on_load),
  757. LUA_INTERFACE_DEF (config, add_periodic),
  758. LUA_INTERFACE_DEF (config, get_symbols_count),
  759. LUA_INTERFACE_DEF (config, get_symbols_cksum),
  760. LUA_INTERFACE_DEF (config, get_symbols_counters),
  761. LUA_INTERFACE_DEF (config, get_symbols_scores),
  762. LUA_INTERFACE_DEF (config, get_symbol_callback),
  763. LUA_INTERFACE_DEF (config, set_symbol_callback),
  764. LUA_INTERFACE_DEF (config, get_symbol_stat),
  765. LUA_INTERFACE_DEF (config, register_finish_script),
  766. LUA_INTERFACE_DEF (config, register_monitored),
  767. LUA_INTERFACE_DEF (config, add_doc),
  768. LUA_INTERFACE_DEF (config, add_example),
  769. LUA_INTERFACE_DEF (config, set_peak_cb),
  770. LUA_INTERFACE_DEF (config, get_cpu_flags),
  771. LUA_INTERFACE_DEF (config, has_torch),
  772. LUA_INTERFACE_DEF (config, experimental_enabled),
  773. LUA_INTERFACE_DEF (config, load_ucl),
  774. LUA_INTERFACE_DEF (config, parse_rcl),
  775. LUA_INTERFACE_DEF (config, init_modules),
  776. LUA_INTERFACE_DEF (config, init_subsystem),
  777. LUA_INTERFACE_DEF (config, get_tld_path),
  778. {"__tostring", rspamd_lua_class_tostring},
  779. {"__newindex", lua_config_newindex},
  780. {NULL, NULL}
  781. };
  782. LUA_FUNCTION_DEF (monitored, alive);
  783. LUA_FUNCTION_DEF (monitored, latency);
  784. LUA_FUNCTION_DEF (monitored, offline);
  785. LUA_FUNCTION_DEF (monitored, total_offline);
  786. static const struct luaL_reg monitoredlib_m[] = {
  787. LUA_INTERFACE_DEF (monitored, alive),
  788. LUA_INTERFACE_DEF (monitored, latency),
  789. LUA_INTERFACE_DEF (monitored, offline),
  790. LUA_INTERFACE_DEF (monitored, total_offline),
  791. {"__tostring", rspamd_lua_class_tostring},
  792. {NULL, NULL}
  793. };
  794. static const guint64 rspamd_lua_callback_magic = 0x32c118af1e3263c7ULL;
  795. struct rspamd_config *
  796. lua_check_config (lua_State * L, gint pos)
  797. {
  798. void *ud = rspamd_lua_check_udata (L, pos, "rspamd{config}");
  799. luaL_argcheck (L, ud != NULL, pos, "'config' expected");
  800. return ud ? *((struct rspamd_config **)ud) : NULL;
  801. }
  802. static struct rspamd_monitored *
  803. lua_check_monitored (lua_State * L, gint pos)
  804. {
  805. void *ud = rspamd_lua_check_udata (L, pos, "rspamd{monitored}");
  806. luaL_argcheck (L, ud != NULL, pos, "'monitored' expected");
  807. return ud ? *((struct rspamd_monitored **)ud) : NULL;
  808. }
  809. /*** Config functions ***/
  810. static gint
  811. lua_config_get_api_version (lua_State *L)
  812. {
  813. msg_warn ("get_api_version is deprecated, do not use it");
  814. lua_pushnumber (L, 100);
  815. return 1;
  816. }
  817. static gint
  818. lua_config_get_module_opt (lua_State * L)
  819. {
  820. LUA_TRACE_POINT;
  821. struct rspamd_config *cfg = lua_check_config (L, 1);
  822. const gchar *mname, *optname;
  823. const ucl_object_t *obj;
  824. if (cfg) {
  825. mname = luaL_checkstring (L, 2);
  826. optname = luaL_checkstring (L, 3);
  827. if (mname && optname) {
  828. obj = rspamd_config_get_module_opt (cfg, mname, optname);
  829. if (obj) {
  830. return ucl_object_push_lua (L, obj, TRUE);
  831. }
  832. }
  833. }
  834. lua_pushnil (L);
  835. return 1;
  836. }
  837. static int
  838. lua_config_get_mempool (lua_State * L)
  839. {
  840. LUA_TRACE_POINT;
  841. rspamd_mempool_t **ppool;
  842. struct rspamd_config *cfg = lua_check_config (L, 1);
  843. if (cfg != NULL) {
  844. ppool = lua_newuserdata (L, sizeof (rspamd_mempool_t *));
  845. rspamd_lua_setclass (L, "rspamd{mempool}", -1);
  846. *ppool = cfg->cfg_pool;
  847. }
  848. else {
  849. lua_pushnil (L);
  850. }
  851. return 1;
  852. }
  853. static int
  854. lua_config_get_resolver (lua_State * L)
  855. {
  856. LUA_TRACE_POINT;
  857. struct rspamd_dns_resolver **pres;
  858. struct rspamd_config *cfg = lua_check_config (L, 1);
  859. if (cfg != NULL && cfg->dns_resolver) {
  860. pres = lua_newuserdata (L, sizeof (*pres));
  861. rspamd_lua_setclass (L, "rspamd{resolver}", -1);
  862. *pres = cfg->dns_resolver;
  863. }
  864. else {
  865. lua_pushnil (L);
  866. }
  867. return 1;
  868. }
  869. static gint
  870. lua_config_get_all_opt (lua_State * L)
  871. {
  872. LUA_TRACE_POINT;
  873. struct rspamd_config *cfg = lua_check_config (L, 1);
  874. const gchar *mname;
  875. const ucl_object_t *obj, *cur, *cur_elt;
  876. ucl_object_iter_t it = NULL;
  877. gint i;
  878. if (cfg) {
  879. mname = luaL_checkstring (L, 2);
  880. if (mname) {
  881. obj = ucl_obj_get_key (cfg->rcl_obj, mname);
  882. /* Flatten object */
  883. if (obj != NULL && (ucl_object_type (obj) == UCL_OBJECT ||
  884. ucl_object_type (obj) == UCL_ARRAY)) {
  885. lua_newtable (L);
  886. it = ucl_object_iterate_new (obj);
  887. LL_FOREACH (obj, cur) {
  888. it = ucl_object_iterate_reset (it, cur);
  889. while ((cur_elt = ucl_object_iterate_safe (it, true))) {
  890. lua_pushstring (L, ucl_object_key (cur_elt));
  891. ucl_object_push_lua (L, cur_elt, true);
  892. lua_settable (L, -3);
  893. }
  894. }
  895. ucl_object_iterate_free (it);
  896. return 1;
  897. }
  898. else if (obj != NULL) {
  899. lua_newtable (L);
  900. i = 1;
  901. LL_FOREACH (obj, cur) {
  902. lua_pushinteger (L, i++);
  903. ucl_object_push_lua (L, cur, true);
  904. lua_settable (L, -3);
  905. }
  906. return 1;
  907. }
  908. }
  909. }
  910. lua_pushnil (L);
  911. return 1;
  912. }
  913. struct rspamd_lua_cached_config {
  914. lua_State *L;
  915. gint ref;
  916. };
  917. static void
  918. lua_config_ucl_dtor (gpointer p)
  919. {
  920. struct rspamd_lua_cached_config *cached = p;
  921. luaL_unref (cached->L, LUA_REGISTRYINDEX, cached->ref);
  922. }
  923. static gint
  924. lua_config_get_ucl (lua_State * L)
  925. {
  926. LUA_TRACE_POINT;
  927. struct rspamd_config *cfg = lua_check_config (L, 1);
  928. struct rspamd_lua_cached_config *cached;
  929. if (cfg) {
  930. cached = rspamd_mempool_get_variable (cfg->cfg_pool, "ucl_cached");
  931. if (cached) {
  932. lua_rawgeti (L, LUA_REGISTRYINDEX, cached->ref);
  933. }
  934. else {
  935. ucl_object_push_lua (L, cfg->rcl_obj, true);
  936. lua_pushvalue (L, -1);
  937. cached = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (*cached));
  938. cached->L = L;
  939. cached->ref = luaL_ref (L, LUA_REGISTRYINDEX);
  940. rspamd_mempool_set_variable (cfg->cfg_pool, "ucl_cached",
  941. cached, lua_config_ucl_dtor);
  942. }
  943. }
  944. else {
  945. return luaL_error (L, "invalid arguments");
  946. }
  947. return 1;
  948. }
  949. static gint
  950. lua_config_get_classifier (lua_State * L)
  951. {
  952. LUA_TRACE_POINT;
  953. struct rspamd_config *cfg = lua_check_config (L, 1);
  954. struct rspamd_classifier_config *clc = NULL, **pclc = NULL;
  955. const gchar *name;
  956. GList *cur;
  957. if (cfg) {
  958. name = luaL_checkstring (L, 2);
  959. cur = g_list_first (cfg->classifiers);
  960. while (cur) {
  961. clc = cur->data;
  962. if (g_ascii_strcasecmp (clc->name, name) == 0) {
  963. pclc = &clc;
  964. break;
  965. }
  966. cur = g_list_next (cur);
  967. }
  968. if (pclc) {
  969. pclc = lua_newuserdata (L,
  970. sizeof (struct rspamd_classifier_config *));
  971. rspamd_lua_setclass (L, "rspamd{classifier}", -1);
  972. *pclc = clc;
  973. return 1;
  974. }
  975. }
  976. lua_pushnil (L);
  977. return 1;
  978. }
  979. struct lua_callback_data {
  980. guint64 magic;
  981. lua_State *L;
  982. gchar *symbol;
  983. union {
  984. gchar *name;
  985. gint ref;
  986. } callback;
  987. gboolean cb_is_ref;
  988. /* Dynamic data */
  989. gint stack_level;
  990. gint order;
  991. struct rspamd_symcache_item *item;
  992. };
  993. /*
  994. * Unref symbol if it is local reference
  995. */
  996. static void
  997. lua_destroy_cfg_symbol (gpointer ud)
  998. {
  999. struct lua_callback_data *cd = ud;
  1000. /* Unref callback */
  1001. if (cd->cb_is_ref) {
  1002. luaL_unref (cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
  1003. }
  1004. }
  1005. static gint
  1006. lua_config_register_module_option (lua_State *L)
  1007. {
  1008. return 0;
  1009. }
  1010. static gint
  1011. rspamd_compare_order_func (gconstpointer a, gconstpointer b)
  1012. {
  1013. const struct lua_callback_data *cb1 = a, *cb2 = b;
  1014. /* order of call goes from lower to higher */
  1015. return cb2->order - cb1->order;
  1016. }
  1017. static void
  1018. lua_metric_symbol_callback (struct rspamd_task *task,
  1019. struct rspamd_symcache_item *item,
  1020. gpointer ud)
  1021. {
  1022. struct lua_callback_data *cd = ud;
  1023. struct rspamd_task **ptask;
  1024. gint level = lua_gettop (cd->L), nresults, err_idx, ret;
  1025. lua_State *L = cd->L;
  1026. GString *tb;
  1027. struct rspamd_symbol_result *s;
  1028. cd->item = item;
  1029. rspamd_symcache_item_async_inc (task, item, "lua symbol");
  1030. lua_pushcfunction (L, &rspamd_lua_traceback);
  1031. err_idx = lua_gettop (L);
  1032. level ++;
  1033. if (cd->cb_is_ref) {
  1034. lua_rawgeti (L, LUA_REGISTRYINDEX, cd->callback.ref);
  1035. }
  1036. else {
  1037. lua_getglobal (L, cd->callback.name);
  1038. }
  1039. ptask = lua_newuserdata (L, sizeof (struct rspamd_task *));
  1040. rspamd_lua_setclass (L, "rspamd{task}", -1);
  1041. *ptask = task;
  1042. if ((ret = lua_pcall (L, 1, LUA_MULTRET, err_idx)) != 0) {
  1043. tb = lua_touserdata (L, -1);
  1044. msg_err_task ("call to (%s) failed (%d): %v", cd->symbol, ret, tb);
  1045. if (tb) {
  1046. g_string_free (tb, TRUE);
  1047. lua_pop (L, 1);
  1048. }
  1049. }
  1050. else {
  1051. nresults = lua_gettop (L) - level;
  1052. if (nresults >= 1) {
  1053. /* Function returned boolean, so maybe we need to insert result? */
  1054. gint res = 0;
  1055. gint i;
  1056. gdouble flag = 1.0;
  1057. gint type;
  1058. type = lua_type (cd->L, level + 1);
  1059. if (type == LUA_TBOOLEAN) {
  1060. res = lua_toboolean (L, level + 1);
  1061. }
  1062. else if (type == LUA_TNUMBER) {
  1063. res = lua_tonumber (L, level + 1);
  1064. }
  1065. else if (type == LUA_TNIL) {
  1066. /* Can happen sometimes... */
  1067. res = FALSE;
  1068. }
  1069. else {
  1070. g_assert_not_reached ();
  1071. }
  1072. if (res) {
  1073. gint first_opt = 2;
  1074. if (lua_type (L, level + 2) == LUA_TNUMBER) {
  1075. flag = lua_tonumber (L, level + 2);
  1076. /* Shift opt index */
  1077. first_opt = 3;
  1078. }
  1079. else {
  1080. flag = res;
  1081. }
  1082. s = rspamd_task_insert_result (task, cd->symbol, flag, NULL);
  1083. if (s) {
  1084. guint last_pos = lua_gettop (L);
  1085. for (i = level + first_opt; i <= last_pos; i++) {
  1086. if (lua_type (L, i) == LUA_TSTRING) {
  1087. const char *opt = lua_tostring (L, i);
  1088. rspamd_task_add_result_option (task, s, opt);
  1089. }
  1090. else if (lua_type (L, i) == LUA_TTABLE) {
  1091. lua_pushvalue (L, i);
  1092. for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
  1093. const char *opt = lua_tostring (L, -1);
  1094. rspamd_task_add_result_option (task, s, opt);
  1095. }
  1096. lua_pop (L, 1);
  1097. }
  1098. }
  1099. }
  1100. }
  1101. lua_pop (L, nresults);
  1102. }
  1103. }
  1104. lua_pop (L, 1); /* Error function */
  1105. rspamd_symcache_item_async_dec_check (task, cd->item, "lua symbol");
  1106. g_assert (lua_gettop (L) == level - 1);
  1107. }
  1108. static void lua_metric_symbol_callback_return (struct thread_entry *thread_entry,
  1109. int ret);
  1110. static void lua_metric_symbol_callback_error (struct thread_entry *thread_entry,
  1111. int ret,
  1112. const char *msg);
  1113. static void
  1114. lua_metric_symbol_callback_coro (struct rspamd_task *task,
  1115. struct rspamd_symcache_item *item,
  1116. gpointer ud)
  1117. {
  1118. struct lua_callback_data *cd = ud;
  1119. struct rspamd_task **ptask;
  1120. struct thread_entry *thread_entry;
  1121. rspamd_symcache_item_async_inc (task, item, "lua coro symbol");
  1122. thread_entry = lua_thread_pool_get_for_task (task);
  1123. g_assert(thread_entry->cd == NULL);
  1124. thread_entry->cd = cd;
  1125. lua_State *thread = thread_entry->lua_state;
  1126. cd->stack_level = lua_gettop (thread);
  1127. cd->item = item;
  1128. if (cd->cb_is_ref) {
  1129. lua_rawgeti (thread, LUA_REGISTRYINDEX, cd->callback.ref);
  1130. }
  1131. else {
  1132. lua_getglobal (thread, cd->callback.name);
  1133. }
  1134. ptask = lua_newuserdata (thread, sizeof (struct rspamd_task *));
  1135. rspamd_lua_setclass (thread, "rspamd{task}", -1);
  1136. *ptask = task;
  1137. thread_entry->finish_callback = lua_metric_symbol_callback_return;
  1138. thread_entry->error_callback = lua_metric_symbol_callback_error;
  1139. lua_thread_call (thread_entry, 1);
  1140. }
  1141. static void
  1142. lua_metric_symbol_callback_error (struct thread_entry *thread_entry,
  1143. int ret,
  1144. const char *msg)
  1145. {
  1146. struct lua_callback_data *cd = thread_entry->cd;
  1147. struct rspamd_task *task = thread_entry->task;
  1148. msg_err_task ("call to coroutine (%s) failed (%d): %s", cd->symbol, ret, msg);
  1149. rspamd_symcache_item_async_dec_check (task, cd->item, "lua coro symbol");
  1150. }
  1151. static void
  1152. lua_metric_symbol_callback_return (struct thread_entry *thread_entry, int ret)
  1153. {
  1154. struct lua_callback_data *cd = thread_entry->cd;
  1155. struct rspamd_task *task = thread_entry->task;
  1156. int nresults;
  1157. struct rspamd_symbol_result *s;
  1158. (void)ret;
  1159. lua_State *L = thread_entry->lua_state;
  1160. nresults = lua_gettop (L) - cd->stack_level;
  1161. if (nresults >= 1) {
  1162. /* Function returned boolean, so maybe we need to insert result? */
  1163. gint res = 0;
  1164. gint i;
  1165. gdouble flag = 1.0;
  1166. gint type;
  1167. type = lua_type (L, cd->stack_level + 1);
  1168. if (type == LUA_TBOOLEAN) {
  1169. res = lua_toboolean (L, cd->stack_level + 1);
  1170. }
  1171. else if (type == LUA_TFUNCTION) {
  1172. g_assert_not_reached ();
  1173. }
  1174. else {
  1175. res = lua_tonumber (L, cd->stack_level + 1);
  1176. }
  1177. if (res) {
  1178. gint first_opt = 2;
  1179. if (lua_type (L, cd->stack_level + 2) == LUA_TNUMBER) {
  1180. flag = lua_tonumber (L, cd->stack_level + 2);
  1181. /* Shift opt index */
  1182. first_opt = 3;
  1183. }
  1184. else {
  1185. flag = res;
  1186. }
  1187. s = rspamd_task_insert_result (task, cd->symbol, flag, NULL);
  1188. if (s) {
  1189. guint last_pos = lua_gettop (L);
  1190. for (i = cd->stack_level + first_opt; i <= last_pos; i++) {
  1191. if (lua_type (L, i) == LUA_TSTRING) {
  1192. const char *opt = lua_tostring (L, i);
  1193. rspamd_task_add_result_option (task, s, opt);
  1194. }
  1195. else if (lua_type (L, i) == LUA_TTABLE) {
  1196. lua_pushvalue (L, i);
  1197. for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
  1198. const char *opt = lua_tostring (L, -1);
  1199. rspamd_task_add_result_option (task, s, opt);
  1200. }
  1201. lua_pop (L, 1);
  1202. }
  1203. }
  1204. }
  1205. }
  1206. lua_pop (L, nresults);
  1207. }
  1208. g_assert (lua_gettop (L) == cd->stack_level); /* we properly cleaned up the stack */
  1209. cd->stack_level = 0;
  1210. rspamd_symcache_item_async_dec_check (task, cd->item, "lua coro symbol");
  1211. }
  1212. static gint
  1213. rspamd_register_symbol_fromlua (lua_State *L,
  1214. struct rspamd_config *cfg,
  1215. const gchar *name,
  1216. gint ref,
  1217. gdouble weight,
  1218. gint priority,
  1219. enum rspamd_symbol_type type,
  1220. gint parent,
  1221. gboolean optional,
  1222. gboolean no_squeeze)
  1223. {
  1224. struct lua_callback_data *cd;
  1225. gint ret = -1, err_idx;
  1226. if (priority == 0 && weight < 0) {
  1227. priority = 1;
  1228. }
  1229. if ((ret = rspamd_symcache_find_symbol (cfg->cache, name)) != -1) {
  1230. if (optional) {
  1231. msg_debug_config ("duplicate symbol: %s, skip registering", name);
  1232. return ret;
  1233. }
  1234. else {
  1235. msg_err_config ("duplicate symbol: %s, skip registering", name);
  1236. return -1;
  1237. }
  1238. }
  1239. if (ref != -1) {
  1240. if (type & SYMBOL_TYPE_USE_CORO) {
  1241. /* Coroutines are incompatible with squeezing */
  1242. no_squeeze = TRUE;
  1243. }
  1244. /*
  1245. * We call for routine called lua_squeeze_rules.squeeze_rule if it exists
  1246. */
  1247. lua_pushcfunction (L, &rspamd_lua_traceback);
  1248. err_idx = lua_gettop (L);
  1249. if (!no_squeeze && (type & (SYMBOL_TYPE_CALLBACK|SYMBOL_TYPE_NORMAL)) &&
  1250. rspamd_lua_require_function (L, "lua_squeeze_rules", "squeeze_rule")) {
  1251. if (name) {
  1252. lua_pushstring (L, name);
  1253. }
  1254. else {
  1255. lua_pushnil (L);
  1256. }
  1257. /* Push function reference */
  1258. lua_rawgeti (L, LUA_REGISTRYINDEX, ref);
  1259. /* Flags */
  1260. lua_createtable (L, 0, 0);
  1261. if (type & SYMBOL_TYPE_MIME_ONLY) {
  1262. lua_pushstring (L, "mime");
  1263. lua_pushboolean (L, true);
  1264. lua_settable (L, -3);
  1265. }
  1266. if (type & SYMBOL_TYPE_FINE) {
  1267. lua_pushstring (L, "fine");
  1268. lua_pushboolean (L, true);
  1269. lua_settable (L, -3);
  1270. }
  1271. if (type & SYMBOL_TYPE_NOSTAT) {
  1272. lua_pushstring (L, "nostat");
  1273. lua_pushboolean (L, true);
  1274. lua_settable (L, -3);
  1275. }
  1276. if (type & SYMBOL_TYPE_EXPLICIT_DISABLE) {
  1277. lua_pushstring (L, "explicit_disable");
  1278. lua_pushboolean (L, true);
  1279. lua_settable (L, -3);
  1280. }
  1281. /* Now call for squeeze function */
  1282. if (lua_pcall (L, 3, 1, err_idx) != 0) {
  1283. GString *tb = lua_touserdata (L, -1);
  1284. msg_err_config ("call to squeeze_rule failed: %v", tb);
  1285. if (tb) {
  1286. g_string_free (tb, TRUE);
  1287. }
  1288. }
  1289. ret = lua_tonumber (L, -1);
  1290. if (ret == -1) {
  1291. /* Do direct registration */
  1292. cd = rspamd_mempool_alloc0 (cfg->cfg_pool,
  1293. sizeof (struct lua_callback_data));
  1294. cd->magic = rspamd_lua_callback_magic;
  1295. cd->cb_is_ref = TRUE;
  1296. cd->callback.ref = ref;
  1297. cd->L = L;
  1298. if (name) {
  1299. cd->symbol = rspamd_mempool_strdup (cfg->cfg_pool, name);
  1300. }
  1301. if (type & SYMBOL_TYPE_USE_CORO) {
  1302. ret = rspamd_symcache_add_symbol (cfg->cache,
  1303. name,
  1304. priority,
  1305. lua_metric_symbol_callback_coro,
  1306. cd,
  1307. type,
  1308. parent);
  1309. }
  1310. else {
  1311. ret = rspamd_symcache_add_symbol (cfg->cache,
  1312. name,
  1313. priority,
  1314. lua_metric_symbol_callback,
  1315. cd,
  1316. type,
  1317. parent);
  1318. }
  1319. rspamd_mempool_add_destructor (cfg->cfg_pool,
  1320. (rspamd_mempool_destruct_t) lua_destroy_cfg_symbol,
  1321. cd);
  1322. }
  1323. }
  1324. else {
  1325. cd = rspamd_mempool_alloc0 (cfg->cfg_pool,
  1326. sizeof (struct lua_callback_data));
  1327. cd->magic = rspamd_lua_callback_magic;
  1328. cd->cb_is_ref = TRUE;
  1329. cd->callback.ref = ref;
  1330. cd->L = L;
  1331. if (name) {
  1332. cd->symbol = rspamd_mempool_strdup (cfg->cfg_pool, name);
  1333. }
  1334. if (type & SYMBOL_TYPE_USE_CORO) {
  1335. ret = rspamd_symcache_add_symbol (cfg->cache,
  1336. name,
  1337. priority,
  1338. lua_metric_symbol_callback_coro,
  1339. cd,
  1340. type,
  1341. parent);
  1342. }
  1343. else {
  1344. ret = rspamd_symcache_add_symbol (cfg->cache,
  1345. name,
  1346. priority,
  1347. lua_metric_symbol_callback,
  1348. cd,
  1349. type,
  1350. parent);
  1351. }
  1352. rspamd_mempool_add_destructor (cfg->cfg_pool,
  1353. (rspamd_mempool_destruct_t)lua_destroy_cfg_symbol,
  1354. cd);
  1355. }
  1356. /* Cleanup lua stack */
  1357. lua_settop (L, err_idx - 1);
  1358. }
  1359. else {
  1360. ret = rspamd_symcache_add_symbol (cfg->cache,
  1361. name,
  1362. priority,
  1363. NULL,
  1364. NULL,
  1365. type,
  1366. parent);
  1367. }
  1368. return ret;
  1369. }
  1370. static gint
  1371. lua_config_register_post_filter (lua_State *L)
  1372. {
  1373. LUA_TRACE_POINT;
  1374. struct rspamd_config *cfg = lua_check_config (L, 1);
  1375. gint order = 0, cbref, ret;
  1376. if (cfg) {
  1377. if (lua_type (L, 3) == LUA_TNUMBER) {
  1378. order = lua_tonumber (L, 3);
  1379. }
  1380. if (lua_type (L, 2) == LUA_TFUNCTION) {
  1381. lua_pushvalue (L, 2);
  1382. /* Get a reference */
  1383. cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  1384. }
  1385. else {
  1386. return luaL_error (L, "invalid type for callback: %s",
  1387. lua_typename (L, lua_type (L, 2)));
  1388. }
  1389. msg_warn_config ("register_post_filter function is deprecated, "
  1390. "use register_symbol instead");
  1391. ret = rspamd_register_symbol_fromlua (L,
  1392. cfg,
  1393. NULL,
  1394. cbref,
  1395. 1.0,
  1396. order,
  1397. SYMBOL_TYPE_POSTFILTER|SYMBOL_TYPE_CALLBACK,
  1398. -1,
  1399. FALSE,
  1400. TRUE);
  1401. lua_pushboolean (L, ret);
  1402. }
  1403. else {
  1404. return luaL_error (L, "invalid arguments");
  1405. }
  1406. return 1;
  1407. }
  1408. static gint
  1409. lua_config_register_pre_filter (lua_State *L)
  1410. {
  1411. LUA_TRACE_POINT;
  1412. struct rspamd_config *cfg = lua_check_config (L, 1);
  1413. gint order = 0, cbref, ret;
  1414. if (cfg) {
  1415. if (lua_type (L, 3) == LUA_TNUMBER) {
  1416. order = lua_tonumber (L, 3);
  1417. }
  1418. if (lua_type (L, 2) == LUA_TFUNCTION) {
  1419. lua_pushvalue (L, 2);
  1420. /* Get a reference */
  1421. cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  1422. }
  1423. else {
  1424. return luaL_error (L, "invalid type for callback: %s",
  1425. lua_typename (L, lua_type (L, 2)));
  1426. }
  1427. msg_warn_config ("register_pre_filter function is deprecated, "
  1428. "use register_symbol instead");
  1429. ret = rspamd_register_symbol_fromlua (L,
  1430. cfg,
  1431. NULL,
  1432. cbref,
  1433. 1.0,
  1434. order,
  1435. SYMBOL_TYPE_PREFILTER|SYMBOL_TYPE_CALLBACK,
  1436. -1,
  1437. FALSE,
  1438. TRUE);
  1439. lua_pushboolean (L, ret);
  1440. }
  1441. else {
  1442. return luaL_error (L, "invalid arguments");
  1443. }
  1444. return 1;
  1445. }
  1446. static gint
  1447. lua_config_get_key (lua_State *L)
  1448. {
  1449. LUA_TRACE_POINT;
  1450. struct rspamd_config *cfg = lua_check_config (L, 1);
  1451. const gchar *name;
  1452. size_t namelen;
  1453. const ucl_object_t *val;
  1454. name = luaL_checklstring(L, 2, &namelen);
  1455. if (name && cfg) {
  1456. val = ucl_object_lookup_len(cfg->rcl_obj, name, namelen);
  1457. if (val != NULL) {
  1458. ucl_object_push_lua (L, val, val->type != UCL_ARRAY);
  1459. }
  1460. else {
  1461. lua_pushnil (L);
  1462. }
  1463. }
  1464. else {
  1465. return luaL_error (L, "invalid arguments");
  1466. }
  1467. return 1;
  1468. }
  1469. static gint
  1470. lua_parse_symbol_flags (const gchar *str)
  1471. {
  1472. int ret = 0;
  1473. if (str) {
  1474. if (strstr (str, "fine") != NULL) {
  1475. ret |= SYMBOL_TYPE_FINE;
  1476. }
  1477. if (strstr (str, "nice") != NULL) {
  1478. ret |= SYMBOL_TYPE_FINE;
  1479. }
  1480. if (strstr (str, "empty") != NULL) {
  1481. ret |= SYMBOL_TYPE_EMPTY;
  1482. }
  1483. if (strstr (str, "skip") != NULL) {
  1484. ret |= SYMBOL_TYPE_SKIPPED;
  1485. }
  1486. if (strstr (str, "nostat") != NULL) {
  1487. ret |= SYMBOL_TYPE_NOSTAT;
  1488. }
  1489. if (strstr (str, "idempotent") != NULL) {
  1490. ret |= SYMBOL_TYPE_IDEMPOTENT;
  1491. }
  1492. if (strstr (str, "squeezed") != NULL) {
  1493. ret |= SYMBOL_TYPE_SQUEEZED;
  1494. }
  1495. if (strstr (str, "trivial") != NULL) {
  1496. ret |= SYMBOL_TYPE_TRIVIAL;
  1497. }
  1498. if (strstr (str, "mime") != NULL) {
  1499. ret |= SYMBOL_TYPE_MIME_ONLY;
  1500. }
  1501. if (strstr (str, "ignore_passthrough") != NULL) {
  1502. ret |= SYMBOL_TYPE_IGNORE_PASSTHROUGH;
  1503. }
  1504. if (strstr (str, "explicit_disable") != NULL) {
  1505. ret |= SYMBOL_TYPE_EXPLICIT_DISABLE;
  1506. }
  1507. if (strstr (str, "coro") != NULL) {
  1508. ret |= SYMBOL_TYPE_USE_CORO;
  1509. }
  1510. }
  1511. return ret;
  1512. }
  1513. static gint
  1514. lua_parse_symbol_type (const gchar *str)
  1515. {
  1516. gint ret = SYMBOL_TYPE_NORMAL;
  1517. gchar **vec;
  1518. guint i, l;
  1519. if (str) {
  1520. vec = g_strsplit_set (str, ",;", -1);
  1521. if (vec) {
  1522. l = g_strv_length (vec);
  1523. for (i = 0; i < l; i ++) {
  1524. str = vec[i];
  1525. if (g_ascii_strcasecmp (str, "virtual") == 0) {
  1526. ret = SYMBOL_TYPE_VIRTUAL;
  1527. } else if (g_ascii_strcasecmp (str, "callback") == 0) {
  1528. ret = SYMBOL_TYPE_CALLBACK;
  1529. } else if (g_ascii_strcasecmp (str, "normal") == 0) {
  1530. ret = SYMBOL_TYPE_NORMAL;
  1531. } else if (g_ascii_strcasecmp (str, "prefilter") == 0) {
  1532. ret = SYMBOL_TYPE_PREFILTER | SYMBOL_TYPE_GHOST;
  1533. } else if (g_ascii_strcasecmp (str, "postfilter") == 0) {
  1534. ret = SYMBOL_TYPE_POSTFILTER | SYMBOL_TYPE_GHOST;
  1535. } else if (g_ascii_strcasecmp (str, "idempotent") == 0) {
  1536. ret = SYMBOL_TYPE_POSTFILTER | SYMBOL_TYPE_GHOST |
  1537. SYMBOL_TYPE_IDEMPOTENT;
  1538. } else {
  1539. gint fl = 0;
  1540. fl = lua_parse_symbol_flags (str);
  1541. if (fl == 0) {
  1542. msg_warn ("bad type: %s", str);
  1543. }
  1544. else {
  1545. ret |= fl;
  1546. }
  1547. }
  1548. }
  1549. g_strfreev (vec);
  1550. }
  1551. }
  1552. return ret;
  1553. }
  1554. static void
  1555. lua_push_symbol_flags (lua_State *L, guint flags)
  1556. {
  1557. guint i = 1;
  1558. lua_newtable (L);
  1559. if (flags & SYMBOL_TYPE_FINE) {
  1560. lua_pushstring (L, "fine");
  1561. lua_rawseti (L, -2, i++);
  1562. }
  1563. if (flags & SYMBOL_TYPE_EMPTY) {
  1564. lua_pushstring (L, "empty");
  1565. lua_rawseti (L, -2, i++);
  1566. }
  1567. if (flags & SYMBOL_TYPE_SQUEEZED) {
  1568. lua_pushstring (L, "squeezed");
  1569. lua_rawseti (L, -2, i++);
  1570. }
  1571. if (flags & SYMBOL_TYPE_EXPLICIT_DISABLE) {
  1572. lua_pushstring (L, "explicit_disable");
  1573. lua_rawseti (L, -2, i++);
  1574. }
  1575. if (flags & SYMBOL_TYPE_IGNORE_PASSTHROUGH) {
  1576. lua_pushstring (L, "ignore_passthrough");
  1577. lua_rawseti (L, -2, i++);
  1578. }
  1579. if (flags & SYMBOL_TYPE_NOSTAT) {
  1580. lua_pushstring (L, "nostat");
  1581. lua_rawseti (L, -2, i++);
  1582. }
  1583. if (flags & SYMBOL_TYPE_IDEMPOTENT) {
  1584. lua_pushstring (L, "idempotent");
  1585. lua_rawseti (L, -2, i++);
  1586. }
  1587. if (flags & SYMBOL_TYPE_MIME_ONLY) {
  1588. lua_pushstring (L, "mime");
  1589. lua_rawseti (L, -2, i++);
  1590. }
  1591. if (flags & SYMBOL_TYPE_TRIVIAL) {
  1592. lua_pushstring (L, "trivial");
  1593. lua_rawseti (L, -2, i++);
  1594. }
  1595. if (flags & SYMBOL_TYPE_SKIPPED) {
  1596. lua_pushstring (L, "skip");
  1597. lua_rawseti (L, -2, i++);
  1598. }
  1599. }
  1600. static gint
  1601. lua_config_get_symbol_flags (lua_State *L)
  1602. {
  1603. struct rspamd_config *cfg = lua_check_config (L, 1);
  1604. const gchar *name = luaL_checkstring (L, 2);
  1605. guint flags;
  1606. if (cfg && name) {
  1607. flags = rspamd_symcache_get_symbol_flags (cfg->cache,
  1608. name);
  1609. if (flags != 0) {
  1610. lua_push_symbol_flags (L, flags);
  1611. }
  1612. else {
  1613. lua_pushnil (L);
  1614. }
  1615. }
  1616. else {
  1617. return luaL_error (L, "invalid arguments");
  1618. }
  1619. return 1;
  1620. }
  1621. static gint
  1622. lua_config_add_symbol_flags (lua_State *L)
  1623. {
  1624. struct rspamd_config *cfg = lua_check_config (L, 1);
  1625. const gchar *name = luaL_checkstring (L, 2);
  1626. guint flags, new_flags = 0;
  1627. if (cfg && name && lua_istable (L, 3)) {
  1628. for (lua_pushnil (L); lua_next (L, 3); lua_pop (L, 1)) {
  1629. new_flags |= lua_parse_symbol_flags (lua_tostring (L, -1));
  1630. }
  1631. flags = rspamd_symcache_get_symbol_flags (cfg->cache,
  1632. name);
  1633. if (flags != 0) {
  1634. rspamd_symcache_add_symbol_flags (cfg->cache, name, new_flags);
  1635. /* Push old flags */
  1636. lua_push_symbol_flags (L, flags);
  1637. }
  1638. else {
  1639. lua_pushnil (L);
  1640. }
  1641. }
  1642. else {
  1643. return luaL_error (L, "invalid arguments");
  1644. }
  1645. return 1;
  1646. }
  1647. static gint
  1648. lua_config_register_symbol (lua_State * L)
  1649. {
  1650. LUA_TRACE_POINT;
  1651. struct rspamd_config *cfg = lua_check_config (L, 1);
  1652. const gchar *name = NULL, *flags_str = NULL, *type_str = NULL,
  1653. *description = NULL, *group = NULL;
  1654. double weight = 0, score = NAN, parent_float = NAN;
  1655. gboolean one_shot = FALSE, no_squeeze = FALSE;
  1656. gint ret = -1, cbref = -1, type, flags = 0;
  1657. gint64 parent = 0, priority = 0, nshots = 0;
  1658. GError *err = NULL;
  1659. if (cfg) {
  1660. if (!rspamd_lua_parse_table_arguments (L, 2, &err,
  1661. "name=S;weight=N;callback=F;flags=S;type=S;priority=I;parent=D;"
  1662. "score=D;description=S;group=S;one_shot=B;nshots=I;no_squeeze=B",
  1663. &name, &weight, &cbref, &flags_str, &type_str,
  1664. &priority, &parent_float,
  1665. &score, &description, &group, &one_shot, &nshots, &no_squeeze)) {
  1666. msg_err_config ("bad arguments: %e", err);
  1667. g_error_free (err);
  1668. return luaL_error (L, "invalid arguments");
  1669. }
  1670. if (!no_squeeze) {
  1671. no_squeeze = cfg->disable_lua_squeeze;
  1672. }
  1673. if (nshots == 0) {
  1674. nshots = cfg->default_max_shots;
  1675. }
  1676. type = lua_parse_symbol_type (type_str);
  1677. if (!name && !(type & SYMBOL_TYPE_CALLBACK)) {
  1678. return luaL_error (L, "no symbol name but type is not callback");
  1679. }
  1680. else if (!(type & SYMBOL_TYPE_VIRTUAL) && cbref == -1) {
  1681. return luaL_error (L, "no callback for symbol %s", name);
  1682. }
  1683. if (flags_str) {
  1684. /* Turn off squeezing as well for now */
  1685. /* TODO: deal with it */
  1686. no_squeeze = TRUE;
  1687. type |= lua_parse_symbol_flags (flags_str);
  1688. }
  1689. if (isnan (parent_float)) {
  1690. parent = -1;
  1691. }
  1692. else {
  1693. parent = parent_float;
  1694. }
  1695. ret = rspamd_register_symbol_fromlua (L,
  1696. cfg,
  1697. name,
  1698. cbref,
  1699. weight == 0 ? 1.0 : weight,
  1700. priority,
  1701. type,
  1702. parent,
  1703. FALSE,
  1704. no_squeeze);
  1705. if (!isnan (score) || group) {
  1706. if (one_shot) {
  1707. nshots = 1;
  1708. }
  1709. if (!isnan (score)) {
  1710. rspamd_config_add_symbol (cfg, name,
  1711. score, description, group, flags,
  1712. (guint) priority, nshots);
  1713. }
  1714. else {
  1715. rspamd_config_add_symbol (cfg, name,
  1716. 0.0, description, group, flags,
  1717. (guint) priority, nshots);
  1718. }
  1719. lua_pushstring (L, "groups");
  1720. lua_gettable (L, 2);
  1721. if (lua_istable (L, -1)) {
  1722. for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
  1723. if (lua_isstring (L, -1)) {
  1724. rspamd_config_add_symbol_group (cfg, name,
  1725. lua_tostring (L, -1));
  1726. }
  1727. else {
  1728. return luaL_error (L, "invalid groups element");
  1729. }
  1730. }
  1731. }
  1732. lua_pop (L, 1);
  1733. }
  1734. }
  1735. else {
  1736. return luaL_error (L, "invalid arguments");
  1737. }
  1738. lua_pushinteger (L, ret);
  1739. return 1;
  1740. }
  1741. static gint
  1742. lua_config_register_symbols (lua_State *L)
  1743. {
  1744. LUA_TRACE_POINT;
  1745. struct rspamd_config *cfg = lua_check_config (L, 1);
  1746. gint i, top, idx, ret = -1;
  1747. const gchar *sym;
  1748. gdouble weight = 1.0;
  1749. if (lua_gettop (L) < 3) {
  1750. if (cfg) {
  1751. msg_err_config ("not enough arguments to register a function");
  1752. }
  1753. lua_error (L);
  1754. return 0;
  1755. }
  1756. if (cfg) {
  1757. if (lua_type (L, 2) == LUA_TSTRING) {
  1758. lua_getglobal (L, luaL_checkstring (L, 2));
  1759. }
  1760. else {
  1761. lua_pushvalue (L, 2);
  1762. }
  1763. idx = luaL_ref (L, LUA_REGISTRYINDEX);
  1764. if (lua_type (L, 3) == LUA_TNUMBER) {
  1765. weight = lua_tonumber (L, 3);
  1766. top = 4;
  1767. }
  1768. else {
  1769. top = 3;
  1770. }
  1771. sym = luaL_checkstring (L, top ++);
  1772. ret = rspamd_register_symbol_fromlua (L,
  1773. cfg,
  1774. sym,
  1775. idx,
  1776. weight,
  1777. 0,
  1778. SYMBOL_TYPE_CALLBACK,
  1779. -1,
  1780. FALSE,
  1781. FALSE);
  1782. for (i = top; i <= lua_gettop (L); i++) {
  1783. if (lua_type (L, i) == LUA_TTABLE) {
  1784. lua_pushvalue (L, i);
  1785. lua_pushnil (L);
  1786. while (lua_next (L, -2)) {
  1787. lua_pushvalue (L, -2);
  1788. sym = luaL_checkstring (L, -2);
  1789. rspamd_symcache_add_symbol (cfg->cache, sym,
  1790. 0, NULL, NULL,
  1791. SYMBOL_TYPE_VIRTUAL, ret);
  1792. lua_pop (L, 2);
  1793. }
  1794. lua_pop (L, 1);
  1795. }
  1796. else if (lua_type (L, i) == LUA_TSTRING) {
  1797. sym = luaL_checkstring (L, i);
  1798. rspamd_symcache_add_symbol (cfg->cache, sym,
  1799. 0, NULL, NULL,
  1800. SYMBOL_TYPE_VIRTUAL, ret);
  1801. }
  1802. }
  1803. }
  1804. lua_pushinteger (L, ret);
  1805. return 1;
  1806. }
  1807. static gint
  1808. lua_config_register_virtual_symbol (lua_State * L)
  1809. {
  1810. LUA_TRACE_POINT;
  1811. struct rspamd_config *cfg = lua_check_config (L, 1);
  1812. const gchar *name;
  1813. double weight;
  1814. gint ret = -1, parent = -1;
  1815. if (cfg) {
  1816. name = luaL_checkstring (L, 2);
  1817. weight = luaL_checknumber (L, 3);
  1818. if (lua_gettop (L) > 3) {
  1819. parent = lua_tonumber (L, 4);
  1820. }
  1821. if (name) {
  1822. ret = rspamd_symcache_add_symbol (cfg->cache, name,
  1823. weight > 0 ? 0 : -1, NULL, NULL,
  1824. SYMBOL_TYPE_VIRTUAL, parent);
  1825. }
  1826. }
  1827. lua_pushinteger (L, ret);
  1828. return 1;
  1829. }
  1830. static gint
  1831. lua_config_register_callback_symbol (lua_State * L)
  1832. {
  1833. LUA_TRACE_POINT;
  1834. struct rspamd_config *cfg = lua_check_config (L, 1);
  1835. const gchar *name = NULL;
  1836. double weight;
  1837. gint ret = -1, top = 2;
  1838. if (cfg) {
  1839. if (lua_type (L, 2) == LUA_TSTRING) {
  1840. /* Legacy syntax */
  1841. name = luaL_checkstring (L, 2);
  1842. top ++;
  1843. }
  1844. weight = luaL_checknumber (L, top);
  1845. if (lua_type (L, top + 1) == LUA_TSTRING) {
  1846. lua_getglobal (L, luaL_checkstring (L, top + 1));
  1847. }
  1848. else {
  1849. lua_pushvalue (L, top + 1);
  1850. }
  1851. ret = rspamd_register_symbol_fromlua (L,
  1852. cfg,
  1853. name,
  1854. luaL_ref (L, LUA_REGISTRYINDEX),
  1855. weight,
  1856. 0,
  1857. SYMBOL_TYPE_CALLBACK,
  1858. -1,
  1859. FALSE,
  1860. lua_type (L, top + 1) == LUA_TSTRING);
  1861. }
  1862. lua_pushinteger (L, ret);
  1863. return 1;
  1864. }
  1865. static gint
  1866. lua_config_register_callback_symbol_priority (lua_State * L)
  1867. {
  1868. LUA_TRACE_POINT;
  1869. struct rspamd_config *cfg = lua_check_config (L, 1);
  1870. const gchar *name = NULL;
  1871. double weight;
  1872. gint priority, ret = -1, top = 2;
  1873. if (cfg) {
  1874. if (lua_type (L, 2) == LUA_TSTRING) {
  1875. /* Legacy syntax */
  1876. name = luaL_checkstring (L, 2);
  1877. top ++;
  1878. }
  1879. weight = luaL_checknumber (L, top);
  1880. priority = luaL_checknumber (L, top + 1);
  1881. if (lua_type (L, top + 2) == LUA_TSTRING) {
  1882. lua_getglobal (L, luaL_checkstring (L, top + 2));
  1883. }
  1884. else {
  1885. lua_pushvalue (L, top + 2);
  1886. }
  1887. ret = rspamd_register_symbol_fromlua (L,
  1888. cfg,
  1889. name,
  1890. luaL_ref (L, LUA_REGISTRYINDEX),
  1891. weight,
  1892. priority,
  1893. SYMBOL_TYPE_CALLBACK,
  1894. -1,
  1895. FALSE,
  1896. lua_type (L, top + 2) == LUA_TSTRING);
  1897. }
  1898. lua_pushinteger (L, ret);
  1899. return 1;
  1900. }
  1901. static gboolean
  1902. rspamd_lua_squeeze_dependency (lua_State *L, struct rspamd_config *cfg,
  1903. const gchar *child,
  1904. const gchar *parent)
  1905. {
  1906. gint err_idx;
  1907. gboolean ret = FALSE;
  1908. g_assert (parent != NULL);
  1909. g_assert (child != NULL);
  1910. lua_pushcfunction (L, &rspamd_lua_traceback);
  1911. err_idx = lua_gettop (L);
  1912. if (rspamd_lua_require_function (L, "lua_squeeze_rules", "squeeze_dependency")) {
  1913. lua_pushstring (L, child);
  1914. lua_pushstring (L, parent);
  1915. if (lua_pcall (L, 2, 1, err_idx) != 0) {
  1916. GString *tb = lua_touserdata (L, -1);
  1917. msg_err_config ("call to squeeze_dependency script failed: %v", tb);
  1918. if (tb) {
  1919. g_string_free (tb, TRUE);
  1920. }
  1921. }
  1922. else {
  1923. ret = lua_toboolean (L, -1);
  1924. }
  1925. }
  1926. lua_settop (L, err_idx - 1);
  1927. return ret;
  1928. }
  1929. static gint
  1930. lua_config_register_dependency (lua_State * L)
  1931. {
  1932. LUA_TRACE_POINT;
  1933. struct rspamd_config *cfg = lua_check_config (L, 1);
  1934. const gchar *parent = NULL, *child = NULL;
  1935. gint child_id;
  1936. gboolean skip_squeeze;
  1937. if (cfg == NULL) {
  1938. lua_error (L);
  1939. return 0;
  1940. }
  1941. skip_squeeze = cfg->disable_lua_squeeze;
  1942. if (lua_type (L, 2) == LUA_TNUMBER) {
  1943. child_id = luaL_checknumber (L, 2);
  1944. parent = luaL_checkstring (L, 3);
  1945. if (!skip_squeeze && lua_isboolean (L, 4)) {
  1946. skip_squeeze = lua_toboolean (L, 4);
  1947. }
  1948. msg_warn_config ("calling for obsolete method to register deps for symbol %d->%s",
  1949. child_id, parent);
  1950. if (child_id > 0 && parent != NULL) {
  1951. if (skip_squeeze || !rspamd_lua_squeeze_dependency (L, cfg,
  1952. rspamd_symcache_symbol_by_id (cfg->cache, child_id),
  1953. parent)) {
  1954. rspamd_symcache_add_dependency (cfg->cache, child_id, parent);
  1955. }
  1956. }
  1957. }
  1958. else {
  1959. child = luaL_checkstring (L,2);
  1960. parent = luaL_checkstring (L, 3);
  1961. if (!skip_squeeze && lua_isboolean (L, 4)) {
  1962. skip_squeeze = lua_toboolean (L, 4);
  1963. }
  1964. if (child != NULL && parent != NULL) {
  1965. if (skip_squeeze || !rspamd_lua_squeeze_dependency (L, cfg, child, parent)) {
  1966. rspamd_symcache_add_delayed_dependency (cfg->cache, child,
  1967. parent);
  1968. }
  1969. }
  1970. }
  1971. return 0;
  1972. }
  1973. static gint
  1974. lua_config_set_metric_symbol (lua_State * L)
  1975. {
  1976. LUA_TRACE_POINT;
  1977. struct rspamd_config *cfg = lua_check_config (L, 1);
  1978. const gchar *description = NULL,
  1979. *group = NULL, *name = NULL, *flags_str = NULL;
  1980. double weight;
  1981. gboolean one_shot = FALSE, one_param = FALSE;
  1982. GError *err = NULL;
  1983. gdouble priority = 0.0;
  1984. guint flags = 0;
  1985. gint64 nshots = 0;
  1986. if (cfg) {
  1987. if (lua_type (L, 2) == LUA_TTABLE) {
  1988. if (!rspamd_lua_parse_table_arguments (L, 2, &err,
  1989. "*name=S;score=N;description=S;"
  1990. "group=S;one_shot=B;one_param=B;priority=N;flags=S;"
  1991. "nshots=I",
  1992. &name, &weight, &description,
  1993. &group, &one_shot, &one_param,
  1994. &priority, &flags_str, &nshots)) {
  1995. msg_err_config ("bad arguments: %e", err);
  1996. g_error_free (err);
  1997. return 0;
  1998. }
  1999. }
  2000. else {
  2001. name = luaL_checkstring (L, 2);
  2002. weight = luaL_checknumber (L, 3);
  2003. if (lua_gettop (L) > 3 && lua_type (L, 4) == LUA_TSTRING) {
  2004. description = luaL_checkstring (L, 4);
  2005. }
  2006. if (lua_gettop (L) > 4 && lua_type (L, 5) == LUA_TSTRING) {
  2007. /* XXX: metrics */
  2008. }
  2009. if (lua_gettop (L) > 5 && lua_type (L, 6) == LUA_TSTRING) {
  2010. group = luaL_checkstring (L, 6);
  2011. }
  2012. if (lua_gettop (L) > 6 && lua_type (L, 7) == LUA_TBOOLEAN) {
  2013. one_shot = lua_toboolean (L, 7);
  2014. }
  2015. }
  2016. if (nshots == 0) {
  2017. nshots = cfg->default_max_shots;
  2018. }
  2019. if (one_shot) {
  2020. nshots = 1;
  2021. }
  2022. if (one_param) {
  2023. flags |= RSPAMD_SYMBOL_FLAG_ONEPARAM;
  2024. }
  2025. if (flags_str) {
  2026. if (strstr (flags_str, "one_shot") != NULL) {
  2027. nshots = 1;
  2028. }
  2029. if (strstr (flags_str, "ignore") != NULL) {
  2030. flags |= RSPAMD_SYMBOL_FLAG_IGNORE;
  2031. }
  2032. if (strstr (flags_str, "one_param") != NULL) {
  2033. flags |= RSPAMD_SYMBOL_FLAG_ONEPARAM;
  2034. }
  2035. }
  2036. rspamd_config_add_symbol (cfg, name,
  2037. weight, description, group, flags, (guint) priority, nshots);
  2038. if (lua_type (L, 2) == LUA_TTABLE) {
  2039. lua_pushstring (L, "groups");
  2040. lua_gettable (L, 2);
  2041. if (lua_istable (L, -1)) {
  2042. for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
  2043. if (lua_isstring (L, -1)) {
  2044. rspamd_config_add_symbol_group (cfg, name,
  2045. lua_tostring (L, -1));
  2046. } else {
  2047. return luaL_error (L, "invalid groups element");
  2048. }
  2049. }
  2050. }
  2051. lua_pop (L, 1);
  2052. }
  2053. }
  2054. else {
  2055. return luaL_error (L, "invalid arguments, rspamd_config expected");
  2056. }
  2057. return 0;
  2058. }
  2059. static gint
  2060. lua_config_get_metric_symbol (lua_State * L)
  2061. {
  2062. LUA_TRACE_POINT;
  2063. struct rspamd_config *cfg = lua_check_config (L, 1);
  2064. const gchar *sym_name = luaL_checkstring (L, 2);
  2065. struct rspamd_symbol *sym_def;
  2066. struct rspamd_symbols_group *sym_group;
  2067. guint i;
  2068. if (cfg && sym_name) {
  2069. sym_def = g_hash_table_lookup (cfg->symbols, sym_name);
  2070. if (sym_def == NULL) {
  2071. lua_pushnil (L);
  2072. }
  2073. else {
  2074. lua_createtable (L, 0, 3);
  2075. lua_pushstring (L, "score");
  2076. lua_pushnumber (L, sym_def->score);
  2077. lua_settable (L, -3);
  2078. if (sym_def->description) {
  2079. lua_pushstring (L, "description");
  2080. lua_pushstring (L, sym_def->description);
  2081. lua_settable (L, -3);
  2082. }
  2083. if (sym_def->gr) {
  2084. lua_pushstring (L, "group");
  2085. lua_pushstring (L, sym_def->gr->name);
  2086. lua_settable (L, -3);
  2087. }
  2088. lua_pushstring (L, "groups");
  2089. lua_createtable (L, sym_def->groups->len, 0);
  2090. PTR_ARRAY_FOREACH (sym_def->groups, i, sym_group) {
  2091. lua_pushstring (L, sym_group->name);
  2092. lua_rawseti (L, -2, i + 1);
  2093. }
  2094. lua_settable (L, -3);
  2095. }
  2096. }
  2097. else {
  2098. luaL_error (L, "Invalid arguments");
  2099. }
  2100. return 1;
  2101. }
  2102. static gint
  2103. lua_config_set_metric_action (lua_State * L)
  2104. {
  2105. LUA_TRACE_POINT;
  2106. struct rspamd_config *cfg = lua_check_config (L, 1);
  2107. const gchar *name = NULL;
  2108. double threshold = NAN;
  2109. GError *err = NULL;
  2110. gdouble priority = 0.0;
  2111. ucl_object_t *obj_tbl = NULL;
  2112. if (cfg) {
  2113. if (lua_type (L, 2) == LUA_TTABLE) {
  2114. if (!rspamd_lua_parse_table_arguments (L, 2, &err,
  2115. "*action=S;score=N;"
  2116. "priority=N",
  2117. &name, &threshold,
  2118. &priority)) {
  2119. msg_err_config ("bad arguments: %e", err);
  2120. g_error_free (err);
  2121. return 0;
  2122. }
  2123. }
  2124. else if (lua_type (L, 2) == LUA_TSTRING && lua_type (L, 3) == LUA_TTABLE) {
  2125. name = lua_tostring (L, 2);
  2126. obj_tbl = ucl_object_lua_import (L, 3);
  2127. if (obj_tbl) {
  2128. if (name) {
  2129. rspamd_config_set_action_score (cfg, name, obj_tbl);
  2130. ucl_object_unref (obj_tbl);
  2131. }
  2132. else {
  2133. ucl_object_unref (obj_tbl);
  2134. return luaL_error (L, "invalid first argument, action name expected");
  2135. }
  2136. }
  2137. else {
  2138. return luaL_error (L, "invalid second argument, table expected");
  2139. }
  2140. }
  2141. else {
  2142. return luaL_error (L, "invalid arguments, table expected");
  2143. }
  2144. if (name != NULL && !isnan (threshold) && threshold != 0) {
  2145. obj_tbl = ucl_object_typed_new (UCL_OBJECT);
  2146. ucl_object_insert_key (obj_tbl, ucl_object_fromdouble (threshold),
  2147. "score", 0, false);
  2148. ucl_object_insert_key (obj_tbl, ucl_object_fromdouble (priority),
  2149. "priority", 0, false);
  2150. rspamd_config_set_action_score (cfg, name, obj_tbl);
  2151. ucl_object_unref (obj_tbl);
  2152. }
  2153. }
  2154. else {
  2155. return luaL_error (L, "invalid arguments, rspamd_config expected");
  2156. }
  2157. return 0;
  2158. }
  2159. static gint
  2160. lua_config_get_metric_action (lua_State * L)
  2161. {
  2162. LUA_TRACE_POINT;
  2163. struct rspamd_config *cfg = lua_check_config (L, 1);
  2164. const gchar *act_name = luaL_checkstring (L, 2);
  2165. struct rspamd_action *act;
  2166. if (cfg && act_name) {
  2167. act = rspamd_config_get_action (cfg, act_name);
  2168. if (act) {
  2169. if (!isnan (act->threshold)) {
  2170. lua_pushnumber (L, act->threshold);
  2171. }
  2172. else {
  2173. lua_pushnil (L);
  2174. }
  2175. }
  2176. else {
  2177. lua_pushnil (L);
  2178. }
  2179. }
  2180. else {
  2181. return luaL_error (L, "invalid arguments, rspamd_config expected");
  2182. }
  2183. return 1;
  2184. }
  2185. static gint
  2186. lua_config_get_all_actions (lua_State * L)
  2187. {
  2188. LUA_TRACE_POINT;
  2189. struct rspamd_config *cfg = lua_check_config (L, 1);
  2190. struct rspamd_action *act, *tmp;
  2191. if (cfg) {
  2192. lua_createtable (L, 0, HASH_COUNT (cfg->actions));
  2193. HASH_ITER (hh, cfg->actions, act, tmp) {
  2194. if (!isnan (act->threshold)) {
  2195. lua_pushstring (L, act->name);
  2196. lua_pushnumber (L, act->threshold);
  2197. lua_settable (L, -3);
  2198. }
  2199. }
  2200. }
  2201. else {
  2202. return luaL_error (L, "invalid arguments, rspamd_config expected");
  2203. }
  2204. return 1;
  2205. }
  2206. static gint
  2207. lua_config_add_composite (lua_State * L)
  2208. {
  2209. LUA_TRACE_POINT;
  2210. struct rspamd_config *cfg = lua_check_config (L, 1);
  2211. struct rspamd_expression *expr;
  2212. gchar *name;
  2213. const gchar *expr_str;
  2214. struct rspamd_composite *composite;
  2215. gboolean ret = FALSE, new = TRUE;
  2216. GError *err = NULL;
  2217. if (cfg) {
  2218. name = rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2));
  2219. expr_str = luaL_checkstring (L, 3);
  2220. if (name && expr_str) {
  2221. if (!rspamd_parse_expression (expr_str, 0, &composite_expr_subr,
  2222. NULL, cfg->cfg_pool, &err, &expr)) {
  2223. msg_err_config ("cannot parse composite expression %s: %e",
  2224. expr_str,
  2225. err);
  2226. g_error_free (err);
  2227. }
  2228. else {
  2229. if (g_hash_table_lookup (cfg->composite_symbols, name) != NULL) {
  2230. msg_warn_config ("composite %s is redefined", name);
  2231. new = FALSE;
  2232. }
  2233. composite = rspamd_mempool_alloc0 (cfg->cfg_pool,
  2234. sizeof (struct rspamd_composite));
  2235. composite->expr = expr;
  2236. composite->id = g_hash_table_size (cfg->composite_symbols);
  2237. composite->str_expr = rspamd_mempool_strdup (cfg->cfg_pool,
  2238. expr_str);
  2239. composite->sym = name;
  2240. g_hash_table_insert (cfg->composite_symbols,
  2241. (gpointer)name,
  2242. composite);
  2243. if (new) {
  2244. rspamd_symcache_add_symbol (cfg->cache, name,
  2245. 0, NULL, composite, SYMBOL_TYPE_COMPOSITE, -1);
  2246. }
  2247. ret = TRUE;
  2248. }
  2249. }
  2250. }
  2251. lua_pushboolean (L, ret);
  2252. return 1;
  2253. }
  2254. static gint
  2255. lua_config_newindex (lua_State *L)
  2256. {
  2257. LUA_TRACE_POINT;
  2258. struct rspamd_config *cfg = lua_check_config (L, 1);
  2259. const gchar *name;
  2260. gint id, nshots, flags = 0;
  2261. gboolean optional = FALSE, no_squeeze = FALSE;
  2262. name = luaL_checkstring (L, 2);
  2263. if (cfg != NULL && name != NULL && lua_gettop (L) == 3) {
  2264. no_squeeze = cfg->disable_lua_squeeze;
  2265. if (lua_type (L, 3) == LUA_TFUNCTION) {
  2266. /* Normal symbol from just a function */
  2267. lua_pushvalue (L, 3);
  2268. rspamd_register_symbol_fromlua (L,
  2269. cfg,
  2270. name,
  2271. luaL_ref (L, LUA_REGISTRYINDEX),
  2272. 1.0,
  2273. 0,
  2274. SYMBOL_TYPE_NORMAL,
  2275. -1,
  2276. FALSE,
  2277. no_squeeze);
  2278. }
  2279. else if (lua_type (L, 3) == LUA_TTABLE) {
  2280. gint type = SYMBOL_TYPE_NORMAL, priority = 0, idx;
  2281. gdouble weight = 1.0, score = NAN;
  2282. const char *type_str, *group = NULL, *description = NULL;
  2283. no_squeeze = cfg->disable_lua_squeeze;
  2284. /*
  2285. * Table can have the following attributes:
  2286. * "callback" - should be a callback function
  2287. * "weight" - optional weight
  2288. * "priority" - optional priority
  2289. * "type" - optional type (normal, virtual, callback)
  2290. * "flags" - optional flags
  2291. * -- Metric options
  2292. * "score" - optional default score (overridden by metric)
  2293. * "group" - optional default group
  2294. * "one_shot" - optional one shot mode
  2295. * "description" - optional description
  2296. */
  2297. lua_pushvalue (L, 3);
  2298. lua_pushstring (L, "callback");
  2299. lua_gettable (L, -2);
  2300. if (lua_type (L, -1) != LUA_TFUNCTION) {
  2301. lua_pop (L, 2);
  2302. msg_info_config ("cannot find callback definition for %s",
  2303. name);
  2304. return 0;
  2305. }
  2306. idx = luaL_ref (L, LUA_REGISTRYINDEX);
  2307. /* Optional fields */
  2308. lua_pushstring (L, "weight");
  2309. lua_gettable (L, -2);
  2310. if (lua_type (L, -1) == LUA_TNUMBER) {
  2311. weight = lua_tonumber (L, -1);
  2312. }
  2313. lua_pop (L, 1);
  2314. lua_pushstring (L, "priority");
  2315. lua_gettable (L, -2);
  2316. if (lua_type (L, -1) == LUA_TNUMBER) {
  2317. priority = lua_tonumber (L, -1);
  2318. }
  2319. lua_pop (L, 1);
  2320. lua_pushstring (L, "optional");
  2321. lua_gettable (L, -2);
  2322. if (lua_type (L, -1) == LUA_TBOOLEAN) {
  2323. optional = lua_toboolean (L, -1);
  2324. }
  2325. lua_pop (L, 1);
  2326. lua_pushstring (L, "type");
  2327. lua_gettable (L, -2);
  2328. if (lua_type (L, -1) == LUA_TSTRING) {
  2329. type_str = lua_tostring (L, -1);
  2330. type = lua_parse_symbol_type (type_str);
  2331. }
  2332. lua_pop (L, 1);
  2333. lua_pushstring (L, "flags");
  2334. lua_gettable (L, -2);
  2335. if (lua_type (L, -1) == LUA_TSTRING) {
  2336. type_str = lua_tostring (L, -1);
  2337. type |= lua_parse_symbol_flags (type_str);
  2338. }
  2339. lua_pop (L, 1);
  2340. lua_pushstring (L, "condition");
  2341. lua_gettable (L, -2);
  2342. if (lua_type (L, -1) == LUA_TFUNCTION) {
  2343. no_squeeze = TRUE;
  2344. }
  2345. lua_pop (L, 1);
  2346. if (!no_squeeze) {
  2347. lua_pushstring (L, "no_squeeze");
  2348. lua_gettable (L, -2);
  2349. if (lua_toboolean (L, -1)) {
  2350. no_squeeze = TRUE;
  2351. }
  2352. lua_pop (L, 1);
  2353. }
  2354. id = rspamd_register_symbol_fromlua (L,
  2355. cfg,
  2356. name,
  2357. idx,
  2358. weight,
  2359. priority,
  2360. type,
  2361. -1,
  2362. optional,
  2363. no_squeeze);
  2364. if (id != -1) {
  2365. /* Check for condition */
  2366. lua_pushstring (L, "condition");
  2367. lua_gettable (L, -2);
  2368. if (lua_type (L, -1) == LUA_TFUNCTION) {
  2369. gint condref;
  2370. /* Here we pop function from the stack, so no lua_pop is required */
  2371. condref = luaL_ref (L, LUA_REGISTRYINDEX);
  2372. g_assert (name != NULL);
  2373. rspamd_symcache_add_condition_delayed (cfg->cache,
  2374. name, L, condref);
  2375. }
  2376. else {
  2377. lua_pop (L, 1);
  2378. }
  2379. }
  2380. /*
  2381. * Now check if a symbol has not been registered in any metric and
  2382. * insert default value if applicable
  2383. */
  2384. if (g_hash_table_lookup (cfg->symbols, name) == NULL) {
  2385. nshots = cfg->default_max_shots;
  2386. lua_pushstring (L, "score");
  2387. lua_gettable (L, -2);
  2388. if (lua_type (L, -1) == LUA_TNUMBER) {
  2389. score = lua_tonumber (L, -1);
  2390. }
  2391. lua_pop (L, 1);
  2392. lua_pushstring (L, "group");
  2393. lua_gettable (L, -2);
  2394. if (lua_type (L, -1) == LUA_TSTRING) {
  2395. group = lua_tostring (L, -1);
  2396. }
  2397. lua_pop (L, 1);
  2398. if (!isnan (score) || group != NULL) {
  2399. lua_pushstring (L, "description");
  2400. lua_gettable (L, -2);
  2401. if (lua_type (L, -1) == LUA_TSTRING) {
  2402. description = lua_tostring (L, -1);
  2403. }
  2404. lua_pop (L, 1);
  2405. lua_pushstring (L, "one_shot");
  2406. lua_gettable (L, -2);
  2407. if (lua_type (L, -1) == LUA_TBOOLEAN) {
  2408. if (lua_toboolean (L, -1)) {
  2409. nshots = 1;
  2410. }
  2411. }
  2412. lua_pop (L, 1);
  2413. lua_pushstring (L, "one_param");
  2414. lua_gettable (L, -2);
  2415. if (lua_type (L, -1) == LUA_TBOOLEAN) {
  2416. if (lua_toboolean (L, -1)) {
  2417. flags |= RSPAMD_SYMBOL_FLAG_ONEPARAM;
  2418. }
  2419. }
  2420. lua_pop (L, 1);
  2421. /*
  2422. * Do not override the existing symbols (using zero priority),
  2423. * since we are defining default values here
  2424. */
  2425. if (!isnan (score)) {
  2426. rspamd_config_add_symbol (cfg, name, score,
  2427. description, group, flags, 0, nshots);
  2428. }
  2429. else if (group) {
  2430. /* Add with zero score */
  2431. rspamd_config_add_symbol (cfg, name, 0.0,
  2432. description, group, flags, 0, nshots);
  2433. }
  2434. lua_pushstring (L, "groups");
  2435. lua_gettable (L, -2);
  2436. if (lua_istable (L, -1)) {
  2437. for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
  2438. if (lua_isstring (L, -1)) {
  2439. rspamd_config_add_symbol_group (cfg, name,
  2440. lua_tostring (L, -1));
  2441. }
  2442. else {
  2443. return luaL_error (L, "invalid groups element");
  2444. }
  2445. }
  2446. }
  2447. lua_pop (L, 1);
  2448. }
  2449. }
  2450. /* Remove table from stack */
  2451. lua_pop (L, 1);
  2452. }
  2453. }
  2454. else {
  2455. return luaL_error (L, "invalid arguments");
  2456. }
  2457. return 0;
  2458. }
  2459. static gint
  2460. lua_config_add_condition (lua_State *L)
  2461. {
  2462. LUA_TRACE_POINT;
  2463. struct rspamd_config *cfg = lua_check_config (L, 1);
  2464. const gchar *sym = luaL_checkstring (L, 2);
  2465. gboolean ret = FALSE;
  2466. gint condref;
  2467. if (cfg && sym && lua_type (L, 3) == LUA_TFUNCTION) {
  2468. lua_pushvalue (L, 3);
  2469. condref = luaL_ref (L, LUA_REGISTRYINDEX);
  2470. ret = rspamd_symcache_add_condition_delayed (cfg->cache, sym, L,
  2471. condref);
  2472. if (!ret) {
  2473. luaL_unref (L, LUA_REGISTRYINDEX, condref);
  2474. }
  2475. }
  2476. lua_pushboolean (L, ret);
  2477. return 1;
  2478. }
  2479. static gint
  2480. lua_config_set_peak_cb (lua_State *L)
  2481. {
  2482. LUA_TRACE_POINT;
  2483. struct rspamd_config *cfg = lua_check_config (L, 1);
  2484. gint condref;
  2485. if (cfg && lua_type (L, 2) == LUA_TFUNCTION) {
  2486. lua_pushvalue (L, 2);
  2487. condref = luaL_ref (L, LUA_REGISTRYINDEX);
  2488. rspamd_symcache_set_peak_callback (cfg->cache,
  2489. condref);
  2490. }
  2491. return 0;
  2492. }
  2493. static gint
  2494. lua_config_enable_symbol (lua_State *L)
  2495. {
  2496. LUA_TRACE_POINT;
  2497. struct rspamd_config *cfg = lua_check_config (L, 1);
  2498. const gchar *sym = luaL_checkstring (L, 2);
  2499. if (cfg && sym) {
  2500. rspamd_symcache_enable_symbol_perm (cfg->cache, sym);
  2501. }
  2502. else {
  2503. return luaL_error (L, "invalid arguments");
  2504. }
  2505. return 0;
  2506. }
  2507. static gint
  2508. lua_config_disable_symbol (lua_State *L)
  2509. {
  2510. LUA_TRACE_POINT;
  2511. struct rspamd_config *cfg = lua_check_config (L, 1);
  2512. const gchar *sym = luaL_checkstring (L, 2);
  2513. if (cfg && sym) {
  2514. rspamd_symcache_disable_symbol_perm (cfg->cache, sym);
  2515. }
  2516. else {
  2517. return luaL_error (L, "invalid arguments");
  2518. }
  2519. return 0;
  2520. }
  2521. static gint
  2522. lua_config_register_regexp (lua_State *L)
  2523. {
  2524. LUA_TRACE_POINT;
  2525. struct rspamd_config *cfg = lua_check_config (L, 1);
  2526. struct rspamd_lua_regexp *re = NULL;
  2527. rspamd_regexp_t *cache_re;
  2528. const gchar *type_str = NULL, *header_str = NULL;
  2529. gsize header_len = 0;
  2530. GError *err = NULL;
  2531. enum rspamd_re_type type = RSPAMD_RE_BODY;
  2532. gboolean pcre_only = FALSE;
  2533. guint old_flags;
  2534. /*
  2535. * - `re`* : regular expression object
  2536. * - `type`*: type of regular expression:
  2537. * + `mime`: mime regexp
  2538. * + `rawmime`: raw mime regexp
  2539. * + `header`: header regexp
  2540. * + `rawheader`: raw header expression
  2541. * + `body`: raw body regexp
  2542. * + `url`: url regexp
  2543. * - `header`: for header and rawheader regexp means the name of header
  2544. * - `pcre_only`: allow merely pcre for this regexp
  2545. */
  2546. if (cfg != NULL) {
  2547. if (!rspamd_lua_parse_table_arguments (L, 2, &err,
  2548. "*re=U{regexp};*type=S;header=S;pcre_only=B",
  2549. &re, &type_str, &header_str, &pcre_only)) {
  2550. msg_err_config ("cannot get parameters list: %e", err);
  2551. if (err) {
  2552. g_error_free (err);
  2553. }
  2554. }
  2555. else {
  2556. type = rspamd_re_cache_type_from_string (type_str);
  2557. if ((type == RSPAMD_RE_HEADER ||
  2558. type == RSPAMD_RE_RAWHEADER ||
  2559. type == RSPAMD_RE_MIMEHEADER) &&
  2560. header_str == NULL) {
  2561. msg_err_config (
  2562. "header argument is mandatory for header/rawheader regexps");
  2563. }
  2564. else {
  2565. if (pcre_only) {
  2566. old_flags = rspamd_regexp_get_flags (re->re);
  2567. old_flags |= RSPAMD_REGEXP_FLAG_PCRE_ONLY;
  2568. rspamd_regexp_set_flags (re->re, old_flags);
  2569. }
  2570. if (header_str != NULL) {
  2571. /* Include the last \0 */
  2572. header_len = strlen (header_str) + 1;
  2573. }
  2574. cache_re = rspamd_re_cache_add (cfg->re_cache, re->re, type,
  2575. (gpointer) header_str, header_len);
  2576. /*
  2577. * XXX: here are dragons!
  2578. * Actually, lua regexp contains internal rspamd_regexp_t
  2579. * and it owns it.
  2580. * However, after this operation we have some OTHER regexp,
  2581. * which we really would like to use.
  2582. * So we do the following:
  2583. * 1) Remove old re and unref it
  2584. * 2) Replace the internal re with cached one
  2585. * 3) Increase its refcount to share ownership between cache and
  2586. * lua object
  2587. */
  2588. if (cache_re != re->re) {
  2589. rspamd_regexp_unref (re->re);
  2590. re->re = rspamd_regexp_ref (cache_re);
  2591. }
  2592. }
  2593. }
  2594. }
  2595. return 0;
  2596. }
  2597. static gint
  2598. lua_config_replace_regexp (lua_State *L)
  2599. {
  2600. LUA_TRACE_POINT;
  2601. struct rspamd_config *cfg = lua_check_config (L, 1);
  2602. struct rspamd_lua_regexp *old_re = NULL, *new_re = NULL;
  2603. GError *err = NULL;
  2604. if (cfg != NULL) {
  2605. if (!rspamd_lua_parse_table_arguments (L, 2, &err,
  2606. "*old_re=U{regexp};*new_re=U{regexp}",
  2607. &old_re, &new_re)) {
  2608. msg_err_config ("cannot get parameters list: %e", err);
  2609. if (err) {
  2610. g_error_free (err);
  2611. }
  2612. }
  2613. else {
  2614. rspamd_re_cache_replace (cfg->re_cache, old_re->re, new_re->re);
  2615. }
  2616. }
  2617. return 0;
  2618. }
  2619. static gint
  2620. lua_config_register_worker_script (lua_State *L)
  2621. {
  2622. LUA_TRACE_POINT;
  2623. struct rspamd_config *cfg = lua_check_config (L, 1);
  2624. const gchar *worker_type = luaL_checkstring (L, 2), *wtype;
  2625. struct rspamd_worker_conf *cf;
  2626. GList *cur;
  2627. struct rspamd_worker_lua_script *sc;
  2628. gboolean found = FALSE;
  2629. if (cfg == NULL || worker_type == NULL || lua_type (L, 3) != LUA_TFUNCTION) {
  2630. return luaL_error (L, "invalid arguments");
  2631. }
  2632. for (cur = g_list_first (cfg->workers); cur != NULL; cur = g_list_next (cur)) {
  2633. cf = cur->data;
  2634. wtype = g_quark_to_string (cf->type);
  2635. if (g_ascii_strcasecmp (wtype, worker_type) == 0) {
  2636. sc = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*sc));
  2637. lua_pushvalue (L, 3);
  2638. sc->cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  2639. DL_APPEND (cf->scripts, sc);
  2640. found = TRUE;
  2641. }
  2642. }
  2643. lua_pushboolean (L, found);
  2644. return 1;
  2645. }
  2646. static gint
  2647. lua_config_add_on_load (lua_State *L)
  2648. {
  2649. LUA_TRACE_POINT;
  2650. struct rspamd_config *cfg = lua_check_config (L, 1);
  2651. struct rspamd_config_post_load_script *sc;
  2652. if (cfg == NULL || lua_type (L, 2) != LUA_TFUNCTION) {
  2653. return luaL_error (L, "invalid arguments");
  2654. }
  2655. sc = g_malloc0 (sizeof (*sc));
  2656. lua_pushvalue (L, 2);
  2657. sc->cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  2658. DL_APPEND (cfg->on_load, sc);
  2659. return 0;
  2660. }
  2661. static void lua_periodic_callback_finish (struct thread_entry *thread, int ret);
  2662. static void lua_periodic_callback_error (struct thread_entry *thread, int ret, const char *msg);
  2663. struct rspamd_lua_periodic {
  2664. struct event_base *ev_base;
  2665. struct rspamd_config *cfg;
  2666. lua_State *L;
  2667. gdouble timeout;
  2668. struct event ev;
  2669. gint cbref;
  2670. gboolean need_jitter;
  2671. };
  2672. static void
  2673. lua_periodic_callback (gint unused_fd, short what, gpointer ud)
  2674. {
  2675. struct rspamd_lua_periodic *periodic = ud;
  2676. struct rspamd_config **pcfg, *cfg;
  2677. struct event_base **pev_base;
  2678. struct thread_entry *thread;
  2679. lua_State *L;
  2680. thread = lua_thread_pool_get_for_config (periodic->cfg);
  2681. thread->cd = periodic;
  2682. thread->finish_callback = lua_periodic_callback_finish;
  2683. thread->error_callback = lua_periodic_callback_error;
  2684. L = thread->lua_state;
  2685. lua_rawgeti (L, LUA_REGISTRYINDEX, periodic->cbref);
  2686. pcfg = lua_newuserdata (L, sizeof (*pcfg));
  2687. rspamd_lua_setclass (L, "rspamd{config}", -1);
  2688. cfg = periodic->cfg;
  2689. *pcfg = cfg;
  2690. pev_base = lua_newuserdata (L, sizeof (*pev_base));
  2691. rspamd_lua_setclass (L, "rspamd{ev_base}", -1);
  2692. *pev_base = periodic->ev_base;
  2693. event_del (&periodic->ev);
  2694. lua_thread_call (thread, 2);
  2695. }
  2696. static void
  2697. lua_periodic_callback_finish (struct thread_entry *thread, int ret)
  2698. {
  2699. lua_State *L;
  2700. struct rspamd_lua_periodic *periodic = thread->cd;
  2701. gboolean plan_more = FALSE;
  2702. struct timeval tv;
  2703. gdouble timeout = 0.0;
  2704. L = thread->lua_state;
  2705. #ifdef HAVE_EVENT_NO_CACHE_TIME_FUNC
  2706. event_base_update_cache_time (periodic->ev_base);
  2707. #endif
  2708. if (ret == 0) {
  2709. if (lua_type (L, -1) == LUA_TBOOLEAN) {
  2710. plan_more = lua_toboolean (L, -1);
  2711. timeout = periodic->timeout;
  2712. }
  2713. else if (lua_type (L, -1) == LUA_TNUMBER) {
  2714. timeout = lua_tonumber (L, -1);
  2715. plan_more = timeout > 0 ? TRUE : FALSE;
  2716. }
  2717. lua_pop (L, 1); /* Return value */
  2718. }
  2719. if (plan_more) {
  2720. if (periodic->need_jitter) {
  2721. timeout = rspamd_time_jitter (timeout, 0.0);
  2722. }
  2723. double_to_tv (timeout, &tv);
  2724. event_add (&periodic->ev, &tv);
  2725. }
  2726. else {
  2727. luaL_unref (L, LUA_REGISTRYINDEX, periodic->cbref);
  2728. g_free (periodic);
  2729. }
  2730. }
  2731. static void
  2732. lua_periodic_callback_error (struct thread_entry *thread, int ret, const char *msg)
  2733. {
  2734. struct rspamd_config *cfg;
  2735. struct rspamd_lua_periodic *periodic = thread->cd;
  2736. cfg = periodic->cfg;
  2737. msg_err_config ("call to finishing script failed: %s", msg);
  2738. lua_periodic_callback_finish(thread, ret);
  2739. }
  2740. static gint
  2741. lua_config_add_periodic (lua_State *L)
  2742. {
  2743. LUA_TRACE_POINT;
  2744. struct rspamd_config *cfg = lua_check_config (L, 1);
  2745. struct event_base *ev_base = lua_check_ev_base (L, 2);
  2746. gdouble timeout = lua_tonumber (L, 3);
  2747. struct timeval tv;
  2748. struct rspamd_lua_periodic *periodic;
  2749. gboolean need_jitter = FALSE;
  2750. if (cfg == NULL || timeout < 0 || lua_type (L, 4) != LUA_TFUNCTION) {
  2751. return luaL_error (L, "invalid arguments");
  2752. }
  2753. if (lua_type (L, 5) == LUA_TBOOLEAN) {
  2754. need_jitter = lua_toboolean (L, 5);
  2755. }
  2756. periodic = g_malloc0 (sizeof (*periodic));
  2757. periodic->timeout = timeout;
  2758. periodic->L = L;
  2759. periodic->cfg = cfg;
  2760. periodic->ev_base = ev_base;
  2761. periodic->need_jitter = need_jitter;
  2762. lua_pushvalue (L, 4);
  2763. periodic->cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  2764. event_set (&periodic->ev, -1, EV_TIMEOUT, lua_periodic_callback, periodic);
  2765. event_base_set (ev_base, &periodic->ev);
  2766. if (need_jitter) {
  2767. timeout = rspamd_time_jitter (timeout, 0.0);
  2768. }
  2769. double_to_tv (timeout, &tv);
  2770. event_add (&periodic->ev, &tv);
  2771. return 0;
  2772. }
  2773. static gint
  2774. lua_config_get_symbols_count (lua_State *L)
  2775. {
  2776. LUA_TRACE_POINT;
  2777. struct rspamd_config *cfg = lua_check_config (L, 1);
  2778. guint res = 0;
  2779. if (cfg != NULL) {
  2780. res = rspamd_symcache_stats_symbols_count (cfg->cache);
  2781. }
  2782. else {
  2783. return luaL_error (L, "invalid arguments");
  2784. }
  2785. lua_pushinteger (L, res);
  2786. return 1;
  2787. }
  2788. static gint
  2789. lua_config_get_symbols_cksum (lua_State *L)
  2790. {
  2791. LUA_TRACE_POINT;
  2792. struct rspamd_config *cfg = lua_check_config (L, 1);
  2793. guint64 res = 0, *pres;
  2794. if (cfg != NULL) {
  2795. res = rspamd_symcache_get_cksum (cfg->cache);
  2796. }
  2797. else {
  2798. return luaL_error (L, "invalid arguments");
  2799. }
  2800. pres = lua_newuserdata (L, sizeof (res));
  2801. *pres = res;
  2802. rspamd_lua_setclass (L, "rspamd{int64}", -1);
  2803. return 1;
  2804. }
  2805. static gint
  2806. lua_config_get_symbols_counters (lua_State *L)
  2807. {
  2808. LUA_TRACE_POINT;
  2809. struct rspamd_config *cfg = lua_check_config (L, 1);
  2810. ucl_object_t *counters;
  2811. if (cfg != NULL) {
  2812. counters = rspamd_symcache_counters (cfg->cache);
  2813. ucl_object_push_lua (L, counters, true);
  2814. ucl_object_unref (counters);
  2815. }
  2816. else {
  2817. return luaL_error (L, "invalid arguments");
  2818. }
  2819. return 1;
  2820. }
  2821. static void
  2822. lua_metric_symbol_inserter (gpointer k, gpointer v, gpointer ud)
  2823. {
  2824. lua_State *L = (lua_State *) ud;
  2825. const gchar *sym = k;
  2826. struct rspamd_symbol *s = (struct rspamd_symbol *) v;
  2827. lua_pushstring (L, sym);
  2828. lua_createtable (L, 0, 3); /* TODO: add more if needed */
  2829. lua_pushstring (L, "score");
  2830. lua_pushnumber (L, s->score);
  2831. lua_settable (L, -3);
  2832. lua_pushstring (L, "description");
  2833. lua_pushstring (L, s->description);
  2834. lua_settable (L, -3);
  2835. lua_settable (L, -3);
  2836. }
  2837. static gint
  2838. lua_config_get_symbols_scores (lua_State *L)
  2839. {
  2840. LUA_TRACE_POINT;
  2841. struct rspamd_config *cfg = lua_check_config (L, 1);
  2842. if (cfg != NULL) {
  2843. lua_createtable (L, 0, g_hash_table_size (cfg->symbols));
  2844. g_hash_table_foreach (cfg->symbols,
  2845. lua_metric_symbol_inserter,
  2846. L);
  2847. }
  2848. else {
  2849. return luaL_error (L, "invalid arguments");
  2850. }
  2851. return 1;
  2852. }
  2853. static gint
  2854. lua_config_get_symbol_callback (lua_State *L)
  2855. {
  2856. LUA_TRACE_POINT;
  2857. struct rspamd_config *cfg = lua_check_config (L, 1);
  2858. const gchar *sym = luaL_checkstring (L, 2);
  2859. struct rspamd_abstract_callback_data *abs_cbdata;
  2860. struct lua_callback_data *cbd;
  2861. if (cfg != NULL && sym != NULL) {
  2862. abs_cbdata = rspamd_symcache_get_cbdata (cfg->cache, sym);
  2863. if (abs_cbdata == NULL || abs_cbdata->magic != rspamd_lua_callback_magic) {
  2864. lua_pushnil (L);
  2865. }
  2866. else {
  2867. cbd = (struct lua_callback_data *)abs_cbdata;
  2868. if (cbd->cb_is_ref) {
  2869. lua_rawgeti (L, LUA_REGISTRYINDEX, cbd->callback.ref);
  2870. }
  2871. else {
  2872. lua_getglobal (L, cbd->callback.name);
  2873. }
  2874. }
  2875. }
  2876. else {
  2877. return luaL_error (L, "invalid arguments");
  2878. }
  2879. return 1;
  2880. }
  2881. static gint
  2882. lua_config_set_symbol_callback (lua_State *L)
  2883. {
  2884. LUA_TRACE_POINT;
  2885. struct rspamd_config *cfg = lua_check_config (L, 1);
  2886. const gchar *sym = luaL_checkstring (L, 2);
  2887. struct rspamd_abstract_callback_data *abs_cbdata;
  2888. struct lua_callback_data *cbd;
  2889. if (cfg != NULL && sym != NULL && lua_type (L, 3) == LUA_TFUNCTION) {
  2890. abs_cbdata = rspamd_symcache_get_cbdata (cfg->cache, sym);
  2891. if (abs_cbdata == NULL || abs_cbdata->magic != rspamd_lua_callback_magic) {
  2892. lua_pushboolean (L, FALSE);
  2893. }
  2894. else {
  2895. cbd = (struct lua_callback_data *)abs_cbdata;
  2896. if (cbd->cb_is_ref) {
  2897. luaL_unref (L, LUA_REGISTRYINDEX, cbd->callback.ref);
  2898. }
  2899. else {
  2900. cbd->cb_is_ref = TRUE;
  2901. }
  2902. lua_pushvalue (L, 3);
  2903. cbd->callback.ref = luaL_ref (L, LUA_REGISTRYINDEX);
  2904. lua_pushboolean (L, TRUE);
  2905. }
  2906. }
  2907. else {
  2908. return luaL_error (L, "invalid arguments");
  2909. }
  2910. return 1;
  2911. }
  2912. static gint
  2913. lua_config_get_symbol_stat (lua_State *L)
  2914. {
  2915. LUA_TRACE_POINT;
  2916. struct rspamd_config *cfg = lua_check_config (L, 1);
  2917. const gchar *sym = luaL_checkstring (L, 2);
  2918. gdouble freq, stddev, tm;
  2919. guint hits;
  2920. if (cfg != NULL && sym != NULL) {
  2921. if (!rspamd_symcache_stat_symbol (cfg->cache, sym, &freq,
  2922. &stddev, &tm, &hits)) {
  2923. lua_pushnil (L);
  2924. }
  2925. else {
  2926. lua_createtable (L, 0, 4);
  2927. lua_pushstring (L, "frequency");
  2928. lua_pushnumber (L, freq);
  2929. lua_settable (L, -3);
  2930. lua_pushstring (L, "sttdev");
  2931. lua_pushnumber (L, stddev);
  2932. lua_settable (L, -3);
  2933. lua_pushstring (L, "time");
  2934. lua_pushnumber (L, tm);
  2935. lua_settable (L, -3);
  2936. lua_pushstring (L, "hits");
  2937. lua_pushinteger (L, hits);
  2938. lua_settable (L, -3);
  2939. }
  2940. }
  2941. else {
  2942. return luaL_error (L, "invalid arguments");
  2943. }
  2944. return 1;
  2945. }
  2946. static gint
  2947. lua_config_register_finish_script (lua_State *L)
  2948. {
  2949. LUA_TRACE_POINT;
  2950. struct rspamd_config *cfg = lua_check_config (L, 1);
  2951. struct rspamd_config_post_load_script *sc;
  2952. if (cfg != NULL && lua_type (L, 2) == LUA_TFUNCTION) {
  2953. sc = g_malloc0 (sizeof (*sc));
  2954. lua_pushvalue (L, 2);
  2955. sc->cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  2956. DL_APPEND (cfg->finish_callbacks, sc);
  2957. }
  2958. else {
  2959. return luaL_error (L, "invalid arguments");
  2960. }
  2961. return 0;
  2962. }
  2963. static gint
  2964. lua_config_register_monitored (lua_State *L)
  2965. {
  2966. LUA_TRACE_POINT;
  2967. struct rspamd_config *cfg = lua_check_config (L, 1);
  2968. struct rspamd_monitored *m, **pm;
  2969. const gchar *url, *type;
  2970. ucl_object_t *params = NULL;
  2971. url = lua_tostring (L, 2);
  2972. type = lua_tostring (L, 3);
  2973. if (cfg != NULL && url != NULL && type != NULL) {
  2974. if (g_ascii_strcasecmp (type, "dns") == 0) {
  2975. lua_Debug ar;
  2976. if (lua_type (L, 4) == LUA_TTABLE) {
  2977. params = ucl_object_lua_import (L, 4);
  2978. }
  2979. /* Get lua line and source */
  2980. lua_getstack (L, 1, &ar);
  2981. lua_getinfo (L, "nSl", &ar);
  2982. m = rspamd_monitored_create_ (cfg->monitored_ctx, url,
  2983. RSPAMD_MONITORED_DNS, RSPAMD_MONITORED_DEFAULT,
  2984. params, ar.short_src);
  2985. if (m) {
  2986. pm = lua_newuserdata (L, sizeof (*pm));
  2987. *pm = m;
  2988. rspamd_lua_setclass (L, "rspamd{monitored}", -1);
  2989. }
  2990. else {
  2991. lua_pushnil (L);
  2992. }
  2993. if (params) {
  2994. ucl_object_unref (params);
  2995. }
  2996. }
  2997. else {
  2998. return luaL_error (L, "invalid monitored type: %s", type);
  2999. }
  3000. }
  3001. else {
  3002. return luaL_error (L, "invalid arguments");
  3003. }
  3004. return 1;
  3005. }
  3006. static gint
  3007. lua_config_add_doc (lua_State *L)
  3008. {
  3009. LUA_TRACE_POINT;
  3010. struct rspamd_config *cfg;
  3011. const gchar *path = NULL, *option, *doc_string;
  3012. const gchar *type_str = NULL, *default_value = NULL;
  3013. ucl_type_t type = UCL_NULL;
  3014. gboolean required = FALSE;
  3015. GError *err = NULL;
  3016. cfg = lua_check_config (L, 1);
  3017. if (lua_type (L, 2 ) == LUA_TSTRING) {
  3018. path = luaL_checkstring (L, 2);
  3019. }
  3020. option = luaL_checkstring (L, 3);
  3021. doc_string = luaL_checkstring (L, 4);
  3022. if (cfg && option && doc_string) {
  3023. if (lua_type (L, 5) == LUA_TTABLE) {
  3024. if (!rspamd_lua_parse_table_arguments (L, 5, &err,
  3025. "type=S;default=S;required=B",
  3026. &type_str, &default_value, &required)) {
  3027. msg_err_config ("cannot get parameters list: %e", err);
  3028. if (err) {
  3029. g_error_free (err);
  3030. }
  3031. if (type_str) {
  3032. if (!ucl_object_string_to_type (type_str, &type)) {
  3033. msg_err_config ("invalid type: %s", type_str);
  3034. }
  3035. }
  3036. }
  3037. }
  3038. rspamd_rcl_add_doc_by_path (cfg, path, doc_string, option,
  3039. type, NULL, 0, default_value, required);
  3040. }
  3041. else {
  3042. return luaL_error (L, "invalid arguments");
  3043. }
  3044. return 0;
  3045. }
  3046. static gint
  3047. lua_config_add_example (lua_State *L)
  3048. {
  3049. LUA_TRACE_POINT;
  3050. struct rspamd_config *cfg;
  3051. const gchar *path = NULL, *option, *doc_string, *example;
  3052. gsize example_len;
  3053. cfg = lua_check_config (L, 1);
  3054. if (lua_type (L, 2 ) == LUA_TSTRING) {
  3055. path = luaL_checkstring (L, 2);
  3056. }
  3057. option = luaL_checkstring (L, 3);
  3058. doc_string = luaL_checkstring (L, 4);
  3059. example = luaL_checklstring (L, 5, &example_len);
  3060. if (cfg && option && doc_string && example) {
  3061. rspamd_rcl_add_doc_by_example (cfg, path, doc_string, option,
  3062. example, example_len);
  3063. }
  3064. else {
  3065. return luaL_error (L, "invalid arguments");
  3066. }
  3067. return 0;
  3068. }
  3069. static gint
  3070. lua_config_get_cpu_flags (lua_State *L)
  3071. {
  3072. LUA_TRACE_POINT;
  3073. struct rspamd_config *cfg = lua_check_config (L, 1);
  3074. struct rspamd_cryptobox_library_ctx *crypto_ctx;
  3075. if (cfg != NULL) {
  3076. crypto_ctx = cfg->libs_ctx->crypto_ctx;
  3077. lua_newtable (L);
  3078. if (crypto_ctx->cpu_config & CPUID_SSSE3) {
  3079. lua_pushstring (L, "ssse3");
  3080. lua_pushboolean (L, true);
  3081. lua_settable (L, -3);
  3082. }
  3083. if (crypto_ctx->cpu_config & CPUID_SSE41) {
  3084. lua_pushstring (L, "sse41");
  3085. lua_pushboolean (L, true);
  3086. lua_settable (L, -3);
  3087. }
  3088. if (crypto_ctx->cpu_config & CPUID_SSE42) {
  3089. lua_pushstring (L, "sse42");
  3090. lua_pushboolean (L, true);
  3091. lua_settable (L, -3);
  3092. }
  3093. if (crypto_ctx->cpu_config & CPUID_SSE2) {
  3094. lua_pushstring (L, "sse2");
  3095. lua_pushboolean (L, true);
  3096. lua_settable (L, -3);
  3097. }
  3098. if (crypto_ctx->cpu_config & CPUID_SSE3) {
  3099. lua_pushstring (L, "sse3");
  3100. lua_pushboolean (L, true);
  3101. lua_settable (L, -3);
  3102. }
  3103. if (crypto_ctx->cpu_config & CPUID_AVX) {
  3104. lua_pushstring (L, "avx");
  3105. lua_pushboolean (L, true);
  3106. lua_settable (L, -3);
  3107. }
  3108. if (crypto_ctx->cpu_config & CPUID_AVX2) {
  3109. lua_pushstring (L, "avx2");
  3110. lua_pushboolean (L, true);
  3111. lua_settable (L, -3);
  3112. }
  3113. }
  3114. else {
  3115. return luaL_error (L, "invalid arguments");
  3116. }
  3117. return 1;
  3118. }
  3119. static gint
  3120. lua_config_has_torch (lua_State *L)
  3121. {
  3122. LUA_TRACE_POINT;
  3123. struct rspamd_config *cfg = lua_check_config (L, 1);
  3124. struct rspamd_cryptobox_library_ctx *crypto_ctx;
  3125. if (cfg != NULL) {
  3126. crypto_ctx = cfg->libs_ctx->crypto_ctx;
  3127. #if !defined(WITH_TORCH) || !defined(WITH_LUAJIT)
  3128. lua_pushboolean (L, false);
  3129. (void)crypto_ctx;
  3130. #else
  3131. if (crypto_ctx->cpu_config & CPUID_SSE2) {
  3132. lua_pushboolean (L, true);
  3133. }
  3134. else {
  3135. lua_pushboolean (L, false);
  3136. }
  3137. #endif
  3138. }
  3139. else {
  3140. return luaL_error (L, "invalid arguments");
  3141. }
  3142. return 1;
  3143. }
  3144. static gint
  3145. lua_config_experimental_enabled (lua_State *L)
  3146. {
  3147. LUA_TRACE_POINT;
  3148. struct rspamd_config *cfg = lua_check_config (L, 1);
  3149. if (cfg != NULL) {
  3150. lua_pushboolean (L, cfg->enable_experimental);
  3151. }
  3152. else {
  3153. return luaL_error (L, "invalid arguments");
  3154. }
  3155. return 1;
  3156. }
  3157. struct rspamd_lua_include_trace_cbdata {
  3158. lua_State *L;
  3159. gint cbref;
  3160. };
  3161. static void
  3162. lua_include_trace_cb (struct ucl_parser *parser,
  3163. const ucl_object_t *parent,
  3164. const ucl_object_t *args,
  3165. const char *path,
  3166. size_t pathlen,
  3167. void *user_data)
  3168. {
  3169. struct rspamd_lua_include_trace_cbdata *cbdata =
  3170. (struct rspamd_lua_include_trace_cbdata *)user_data;
  3171. gint err_idx;
  3172. GString *tb;
  3173. lua_State *L;
  3174. L = cbdata->L;
  3175. lua_pushcfunction (L, &rspamd_lua_traceback);
  3176. err_idx = lua_gettop (L);
  3177. lua_rawgeti (L, LUA_REGISTRYINDEX, cbdata->cbref);
  3178. /* Current filename */
  3179. lua_pushstring (L, ucl_parser_get_cur_file (parser));
  3180. /* Included filename */
  3181. lua_pushlstring (L, path, pathlen);
  3182. /* Params */
  3183. if (args) {
  3184. ucl_object_push_lua (L, args, true);
  3185. }
  3186. else {
  3187. lua_newtable (L);
  3188. }
  3189. /* Parent */
  3190. if (parent) {
  3191. lua_pushstring (L, ucl_object_key (parent));
  3192. }
  3193. else {
  3194. lua_pushnil (L);
  3195. }
  3196. if (lua_pcall (L, 4, 0, err_idx) != 0) {
  3197. tb = lua_touserdata (L, -1);
  3198. msg_err ("lua call to local include trace failed: %v", tb);
  3199. if (tb) {
  3200. g_string_free (tb, TRUE);
  3201. }
  3202. }
  3203. lua_settop (L, err_idx - 1);
  3204. }
  3205. #define LUA_TABLE_TO_HASH(htb, idx) do { \
  3206. lua_pushstring (L, (idx)); \
  3207. lua_gettable (L, -2); \
  3208. if (lua_isstring (L, -1)) { \
  3209. g_hash_table_insert ((htb), (idx), g_strdup (lua_tostring (L, -1))); \
  3210. } \
  3211. lua_pop (L, 1); \
  3212. } while(0)
  3213. static gint
  3214. lua_config_load_ucl (lua_State *L)
  3215. {
  3216. struct rspamd_config *cfg = lua_check_config (L, 1);
  3217. const gchar *filename;
  3218. GHashTable *paths = g_hash_table_new_full (rspamd_str_hash, rspamd_str_equal,
  3219. NULL, g_free);
  3220. GError *err = NULL;
  3221. if (cfg) {
  3222. if (lua_isstring (L, 2)) {
  3223. filename = lua_tostring (L, 2);
  3224. }
  3225. else {
  3226. filename = RSPAMD_CONFDIR "/rspamd.conf";
  3227. }
  3228. /* Convert rspamd_paths */
  3229. lua_getglobal (L, "rspamd_paths");
  3230. if (lua_istable (L, -1)) {
  3231. LUA_TABLE_TO_HASH(paths, RSPAMD_CONFDIR_INDEX);
  3232. LUA_TABLE_TO_HASH(paths, RSPAMD_LOCAL_CONFDIR_INDEX);
  3233. LUA_TABLE_TO_HASH(paths, RSPAMD_RUNDIR_INDEX);
  3234. LUA_TABLE_TO_HASH(paths, RSPAMD_DBDIR_INDEX);
  3235. LUA_TABLE_TO_HASH(paths, RSPAMD_LOGDIR_INDEX);
  3236. LUA_TABLE_TO_HASH(paths, RSPAMD_WWWDIR_INDEX);
  3237. LUA_TABLE_TO_HASH(paths, RSPAMD_PLUGINSDIR_INDEX);
  3238. LUA_TABLE_TO_HASH(paths, RSPAMD_RULESDIR_INDEX);
  3239. LUA_TABLE_TO_HASH(paths, RSPAMD_LUALIBDIR_INDEX);
  3240. LUA_TABLE_TO_HASH(paths, RSPAMD_PREFIX_INDEX);
  3241. }
  3242. lua_pop (L, 1);
  3243. if (lua_isfunction (L, 3)) {
  3244. struct rspamd_lua_include_trace_cbdata cbd;
  3245. lua_pushvalue (L, 3);
  3246. cbd.cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  3247. cbd.L = L;
  3248. if (!rspamd_config_parse_ucl (cfg, filename, paths,
  3249. lua_include_trace_cb, &cbd, &err)) {
  3250. luaL_unref (L, LUA_REGISTRYINDEX, cbd.cbref);
  3251. lua_pushboolean (L, false);
  3252. lua_pushfstring (L, "failed to load config: %s", err->message);
  3253. g_error_free (err);
  3254. g_hash_table_unref (paths);
  3255. return 2;
  3256. }
  3257. luaL_unref (L, LUA_REGISTRYINDEX, cbd.cbref);
  3258. }
  3259. else {
  3260. if (!rspamd_config_parse_ucl (cfg, filename, paths, NULL, NULL, &err)) {
  3261. lua_pushboolean (L, false);
  3262. lua_pushfstring (L, "failed to load config: %s", err->message);
  3263. g_error_free (err);
  3264. g_hash_table_unref (paths);
  3265. return 2;
  3266. }
  3267. }
  3268. rspamd_rcl_maybe_apply_lua_transform (cfg);
  3269. rspamd_config_calculate_cksum (cfg);
  3270. }
  3271. else {
  3272. return luaL_error (L, "invalid arguments");
  3273. }
  3274. g_hash_table_unref (paths);
  3275. lua_pushboolean (L, true);
  3276. return 1;
  3277. }
  3278. #undef IDX_TO_HASH
  3279. static gint
  3280. lua_config_parse_rcl (lua_State *L)
  3281. {
  3282. LUA_TRACE_POINT;
  3283. struct rspamd_config *cfg = lua_check_config (L, 1);
  3284. GHashTable *excluded = g_hash_table_new_full (rspamd_str_hash, rspamd_str_equal,
  3285. g_free, NULL);
  3286. GError *err = NULL;
  3287. struct rspamd_rcl_section *top;
  3288. if (cfg) {
  3289. if (lua_istable (L, 2)) {
  3290. lua_pushvalue (L, 2);
  3291. for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
  3292. g_hash_table_insert (excluded, g_strdup (lua_tostring (L, -1)),
  3293. GINT_TO_POINTER (-1));
  3294. }
  3295. lua_pop (L, 1);
  3296. }
  3297. top = rspamd_rcl_config_init (cfg, excluded);
  3298. if (!rspamd_rcl_parse (top, cfg, cfg, cfg->cfg_pool, cfg->rcl_obj, &err)) {
  3299. lua_pushboolean (L, false);
  3300. lua_pushfstring (L, "failed to load config: %s", err->message);
  3301. g_error_free (err);
  3302. g_hash_table_unref (excluded);
  3303. rspamd_rcl_section_free (top);
  3304. return 2;
  3305. }
  3306. }
  3307. else {
  3308. return luaL_error (L, "invalid arguments");
  3309. }
  3310. g_hash_table_unref (excluded);
  3311. rspamd_rcl_section_free (top);
  3312. lua_pushboolean (L, true);
  3313. return 1;
  3314. }
  3315. static gint
  3316. lua_config_init_modules (lua_State *L)
  3317. {
  3318. LUA_TRACE_POINT;
  3319. struct rspamd_config *cfg = lua_check_config (L, 1);
  3320. if (cfg != NULL) {
  3321. rspamd_lua_post_load_config (cfg);
  3322. lua_pushboolean (L, rspamd_init_filters (cfg, FALSE));
  3323. }
  3324. else {
  3325. return luaL_error (L, "invalid arguments");
  3326. }
  3327. return 1;
  3328. }
  3329. static gint
  3330. lua_config_init_subsystem (lua_State *L)
  3331. {
  3332. LUA_TRACE_POINT;
  3333. struct rspamd_config *cfg = lua_check_config (L, 1);
  3334. const gchar *subsystem = luaL_checkstring (L, 2);
  3335. gchar **parts;
  3336. guint nparts, i;
  3337. if (cfg != NULL && subsystem != NULL) {
  3338. parts = g_strsplit_set (subsystem, ";,", -1);
  3339. nparts = g_strv_length (parts);
  3340. for (i = 0; i < nparts; i ++) {
  3341. if (strcmp (parts[i], "filters") == 0) {
  3342. rspamd_lua_post_load_config (cfg);
  3343. rspamd_init_filters (cfg, FALSE);
  3344. }
  3345. else if (strcmp (parts[i], "langdet") == 0) {
  3346. cfg->lang_det = rspamd_language_detector_init (cfg);
  3347. }
  3348. else if (strcmp (parts[i], "stat") == 0) {
  3349. rspamd_stat_init (cfg, NULL);
  3350. }
  3351. else if (strcmp (parts[i], "dns") == 0) {
  3352. struct event_base *ev_base = lua_check_ev_base (L, 3);
  3353. if (ev_base) {
  3354. cfg->dns_resolver = dns_resolver_init (rspamd_logger_get_singleton(),
  3355. ev_base,
  3356. cfg);
  3357. }
  3358. else {
  3359. g_strfreev (parts);
  3360. return luaL_error (L, "no event base specified");
  3361. }
  3362. }
  3363. else {
  3364. g_strfreev (parts);
  3365. return luaL_error (L, "invalid param: %s", parts[i]);
  3366. }
  3367. }
  3368. g_strfreev (parts);
  3369. }
  3370. else {
  3371. return luaL_error (L, "invalid arguments");
  3372. }
  3373. return 0;
  3374. }
  3375. static gint
  3376. lua_config_register_re_selector (lua_State *L)
  3377. {
  3378. LUA_TRACE_POINT;
  3379. struct rspamd_config *cfg = lua_check_config (L, 1);
  3380. const gchar *name = luaL_checkstring (L, 2);
  3381. const gchar *selector_str = luaL_checkstring (L, 3);
  3382. const gchar *delimiter = "";
  3383. gint top = lua_gettop (L);
  3384. bool res = false;
  3385. if (cfg && name && selector_str) {
  3386. if (lua_gettop (L) >= 4) {
  3387. delimiter = luaL_checkstring (L, 4);
  3388. }
  3389. if (luaL_dostring (L, "return require \"lua_selectors\"") != 0) {
  3390. msg_warn_config ("cannot require lua_selectors: %s",
  3391. lua_tostring (L, -1));
  3392. }
  3393. else {
  3394. if (lua_type (L, -1) != LUA_TTABLE) {
  3395. msg_warn_config ("lua selectors must return "
  3396. "table and not %s",
  3397. lua_typename (L, lua_type (L, -1)));
  3398. }
  3399. else {
  3400. lua_pushstring (L, "create_selector_closure");
  3401. lua_gettable (L, -2);
  3402. if (lua_type (L, -1) != LUA_TFUNCTION) {
  3403. msg_warn_config ("create_selector_closure must return "
  3404. "function and not %s",
  3405. lua_typename (L, lua_type (L, -1)));
  3406. }
  3407. else {
  3408. gint err_idx, ret;
  3409. GString *tb;
  3410. struct rspamd_config **pcfg;
  3411. lua_pushcfunction (L, &rspamd_lua_traceback);
  3412. err_idx = lua_gettop (L);
  3413. /* Push function */
  3414. lua_pushvalue (L, -2);
  3415. pcfg = lua_newuserdata (L, sizeof (*pcfg));
  3416. rspamd_lua_setclass (L, "rspamd{config}", -1);
  3417. *pcfg = cfg;
  3418. lua_pushstring (L, selector_str);
  3419. lua_pushstring (L, delimiter);
  3420. if ((ret = lua_pcall (L, 3, 1, err_idx)) != 0) {
  3421. tb = lua_touserdata (L, -1);
  3422. msg_err_config ("call to create_selector_closure lua "
  3423. "script failed (%d): %v", ret, tb);
  3424. if (tb) {
  3425. g_string_free (tb, TRUE);
  3426. }
  3427. }
  3428. else {
  3429. if (lua_type (L, -1) != LUA_TFUNCTION) {
  3430. msg_warn_config ("create_selector_closure "
  3431. "invocation must return "
  3432. "function and not %s",
  3433. lua_typename (L, lua_type (L, -1)));
  3434. }
  3435. else {
  3436. ret = luaL_ref (L, LUA_REGISTRYINDEX);
  3437. rspamd_re_cache_add_selector (cfg->re_cache,
  3438. name, ret);
  3439. res = true;
  3440. }
  3441. }
  3442. }
  3443. }
  3444. }
  3445. }
  3446. else {
  3447. return luaL_error (L, "invalid arguments");
  3448. }
  3449. lua_settop (L, top);
  3450. lua_pushboolean (L, res);
  3451. if (res) {
  3452. msg_info_config ("registered regexp selector %s", name);
  3453. }
  3454. return 1;
  3455. }
  3456. static gint
  3457. lua_config_get_tld_path (lua_State *L)
  3458. {
  3459. LUA_TRACE_POINT;
  3460. struct rspamd_config *cfg = lua_check_config (L, 1);
  3461. if (cfg != NULL) {
  3462. lua_pushstring (L, cfg->tld_file);
  3463. }
  3464. else {
  3465. return luaL_error (L, "invalid arguments");
  3466. }
  3467. return 1;
  3468. }
  3469. static gint
  3470. lua_monitored_alive (lua_State *L)
  3471. {
  3472. LUA_TRACE_POINT;
  3473. struct rspamd_monitored *m = lua_check_monitored (L, 1);
  3474. if (m) {
  3475. lua_pushboolean (L, rspamd_monitored_alive (m));
  3476. }
  3477. else {
  3478. return luaL_error (L, "invalid arguments");
  3479. }
  3480. return 1;
  3481. }
  3482. static gint
  3483. lua_monitored_offline (lua_State *L)
  3484. {
  3485. LUA_TRACE_POINT;
  3486. struct rspamd_monitored *m = lua_check_monitored (L, 1);
  3487. if (m) {
  3488. lua_pushnumber (L, rspamd_monitored_offline_time (m));
  3489. }
  3490. else {
  3491. return luaL_error (L, "invalid arguments");
  3492. }
  3493. return 1;
  3494. }
  3495. static gint
  3496. lua_monitored_total_offline (lua_State *L)
  3497. {
  3498. LUA_TRACE_POINT;
  3499. struct rspamd_monitored *m = lua_check_monitored (L, 1);
  3500. if (m) {
  3501. lua_pushnumber (L, rspamd_monitored_total_offline_time (m));
  3502. }
  3503. else {
  3504. return luaL_error (L, "invalid arguments");
  3505. }
  3506. return 1;
  3507. }
  3508. static gint
  3509. lua_monitored_latency (lua_State *L)
  3510. {
  3511. LUA_TRACE_POINT;
  3512. struct rspamd_monitored *m = lua_check_monitored (L, 1);
  3513. if (m) {
  3514. lua_pushnumber (L, rspamd_monitored_latency (m));
  3515. }
  3516. else {
  3517. return luaL_error (L, "invalid arguments");
  3518. }
  3519. return 1;
  3520. }
  3521. void
  3522. luaopen_config (lua_State * L)
  3523. {
  3524. rspamd_lua_new_class (L, "rspamd{config}", configlib_m);
  3525. lua_pop (L, 1);
  3526. rspamd_lua_new_class (L, "rspamd{monitored}", monitoredlib_m);
  3527. lua_pop (L, 1);
  3528. }
  3529. void
  3530. lua_call_finish_script (struct rspamd_config_post_load_script *sc,
  3531. struct rspamd_task *task) {
  3532. struct rspamd_task **ptask;
  3533. struct thread_entry *thread;
  3534. thread = lua_thread_pool_get_for_task (task);
  3535. thread->task = task;
  3536. lua_State *L = thread->lua_state;
  3537. lua_rawgeti (L, LUA_REGISTRYINDEX, sc->cbref);
  3538. ptask = lua_newuserdata (L, sizeof (struct rspamd_task *));
  3539. rspamd_lua_setclass (L, "rspamd{task}", - 1);
  3540. *ptask = task;
  3541. lua_thread_call (thread, 1);
  3542. }