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 108KB

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