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

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