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_common.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. /*
  2. * Copyright (c) 2009-2012, Vsevolod Stakhov
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  17. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  18. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  19. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  20. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  21. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  22. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. */
  24. #include "lua_common.h"
  25. #include "expressions.h"
  26. /* Lua module init function */
  27. #define MODULE_INIT_FUNC "module_init"
  28. const luaL_reg null_reg[] = {
  29. {"__tostring", rspamd_lua_class_tostring},
  30. {NULL, NULL}
  31. };
  32. /* Logger methods */
  33. LUA_FUNCTION_DEF (logger, err);
  34. LUA_FUNCTION_DEF (logger, warn);
  35. LUA_FUNCTION_DEF (logger, info);
  36. LUA_FUNCTION_DEF (logger, debug);
  37. static const struct luaL_reg loggerlib_f[] = {
  38. LUA_INTERFACE_DEF (logger, err),
  39. LUA_INTERFACE_DEF (logger, warn),
  40. LUA_INTERFACE_DEF (logger, info),
  41. LUA_INTERFACE_DEF (logger, debug),
  42. {"__tostring", rspamd_lua_class_tostring},
  43. {NULL, NULL}
  44. };
  45. /* Util functions */
  46. /**
  47. * Create new class and store metatable on top of the stack
  48. * @param L
  49. * @param classname name of class
  50. * @param func table of class methods
  51. */
  52. void
  53. rspamd_lua_new_class (lua_State * L,
  54. const gchar *classname,
  55. const struct luaL_reg *methods)
  56. {
  57. luaL_newmetatable (L, classname); /* mt */
  58. lua_pushstring (L, "__index");
  59. lua_pushvalue (L, -2); /* pushes the metatable */
  60. lua_settable (L, -3); /* metatable.__index = metatable */
  61. lua_pushstring (L, "class"); /* mt,"__index",it,"class" */
  62. lua_pushstring (L, classname); /* mt,"__index",it,"class",classname */
  63. lua_rawset (L, -3); /* mt,"__index",it */
  64. luaL_register (L, NULL, methods);
  65. }
  66. /**
  67. * Create and register new class with static methods and store metatable on top of the stack
  68. */
  69. void
  70. rspamd_lua_new_class_full (lua_State *L,
  71. const gchar *classname,
  72. const gchar *static_name,
  73. const struct luaL_reg *methods,
  74. const struct luaL_reg *func)
  75. {
  76. rspamd_lua_new_class (L, classname, methods);
  77. luaL_register (L, static_name, func);
  78. }
  79. gint
  80. rspamd_lua_class_tostring (lua_State * L)
  81. {
  82. gchar buf[32];
  83. if (!lua_getmetatable (L, 1)) {
  84. goto error;
  85. }
  86. lua_pushstring (L, "__index");
  87. lua_gettable (L, -2);
  88. if (!lua_istable (L, -1)) {
  89. goto error;
  90. }
  91. lua_pushstring (L, "class");
  92. lua_gettable (L, -2);
  93. if (!lua_isstring (L, -1)) {
  94. goto error;
  95. }
  96. snprintf (buf, sizeof (buf), "%p", lua_touserdata (L, 1));
  97. lua_pushfstring (L, "%s: %s", lua_tostring (L, -1), buf);
  98. return 1;
  99. error:
  100. lua_pushstring (L, "invalid object passed to 'lua_common.c:__tostring'");
  101. lua_error (L);
  102. return 1;
  103. }
  104. void
  105. rspamd_lua_setclass (lua_State * L, const gchar *classname, gint objidx)
  106. {
  107. luaL_getmetatable (L, classname);
  108. if (objidx < 0) {
  109. objidx--;
  110. }
  111. lua_setmetatable (L, objidx);
  112. }
  113. /* assume that table is at the top */
  114. void
  115. rspamd_lua_table_set (lua_State * L, const gchar *index, const gchar *value)
  116. {
  117. lua_pushstring (L, index);
  118. if (value) {
  119. lua_pushstring (L, value);
  120. }
  121. else {
  122. lua_pushnil (L);
  123. }
  124. lua_settable (L, -3);
  125. }
  126. const gchar *
  127. rspamd_lua_table_get (lua_State *L, const gchar *index)
  128. {
  129. const gchar *result;
  130. lua_pushstring (L, index);
  131. lua_gettable (L, -2);
  132. if (!lua_isstring (L, -1)) {
  133. return NULL;
  134. }
  135. result = lua_tostring (L, -1);
  136. lua_pop (L, 1);
  137. return result;
  138. }
  139. static void
  140. lua_common_log (GLogLevelFlags level, lua_State *L, const gchar *msg)
  141. {
  142. lua_Debug d;
  143. gchar func_buf[128], *p;
  144. if (lua_getstack (L, 1, &d) == 1) {
  145. (void)lua_getinfo (L, "Sl", &d);
  146. if ((p = strrchr (d.short_src, '/')) == NULL) {
  147. p = d.short_src;
  148. }
  149. else {
  150. p++;
  151. }
  152. rspamd_snprintf (func_buf, sizeof (func_buf), "%s:%d", p,
  153. d.currentline);
  154. if (level == G_LOG_LEVEL_DEBUG) {
  155. rspamd_conditional_debug (rspamd_main->logger,
  156. NULL,
  157. func_buf,
  158. "%s",
  159. msg);
  160. }
  161. else {
  162. rspamd_common_log_function (rspamd_main->logger,
  163. level,
  164. func_buf,
  165. "%s",
  166. msg);
  167. }
  168. }
  169. else {
  170. if (level == G_LOG_LEVEL_DEBUG) {
  171. rspamd_conditional_debug (rspamd_main->logger,
  172. NULL,
  173. __FUNCTION__,
  174. "%s",
  175. msg);
  176. }
  177. else {
  178. rspamd_common_log_function (rspamd_main->logger,
  179. level,
  180. __FUNCTION__,
  181. "%s",
  182. msg);
  183. }
  184. }
  185. }
  186. /*** Logger interface ***/
  187. static gint
  188. lua_logger_err (lua_State * L)
  189. {
  190. const gchar *msg;
  191. msg = luaL_checkstring (L, 1);
  192. lua_common_log (G_LOG_LEVEL_CRITICAL, L, msg);
  193. return 1;
  194. }
  195. static gint
  196. lua_logger_warn (lua_State * L)
  197. {
  198. const gchar *msg;
  199. msg = luaL_checkstring (L, 1);
  200. lua_common_log (G_LOG_LEVEL_WARNING, L, msg);
  201. return 1;
  202. }
  203. static gint
  204. lua_logger_info (lua_State * L)
  205. {
  206. const gchar *msg;
  207. msg = luaL_checkstring (L, 1);
  208. lua_common_log (G_LOG_LEVEL_INFO, L, msg);
  209. return 1;
  210. }
  211. static gint
  212. lua_logger_debug (lua_State * L)
  213. {
  214. const gchar *msg;
  215. msg = luaL_checkstring (L, 1);
  216. lua_common_log (G_LOG_LEVEL_DEBUG, L, msg);
  217. return 1;
  218. }
  219. /*** Init functions ***/
  220. static gint
  221. lua_load_logger (lua_State *L)
  222. {
  223. lua_newtable (L);
  224. luaL_register (L, NULL, loggerlib_f);
  225. return 1;
  226. }
  227. static void
  228. luaopen_logger (lua_State * L)
  229. {
  230. rspamd_lua_add_preload (L, "rspamd_logger", lua_load_logger);
  231. }
  232. static void
  233. lua_add_actions_global (lua_State *L)
  234. {
  235. gint i;
  236. lua_newtable (L);
  237. for (i = METRIC_ACTION_REJECT; i <= METRIC_ACTION_NOACTION; i++) {
  238. lua_pushstring (L, str_action_metric (i));
  239. lua_pushinteger (L, i);
  240. lua_settable (L, -3);
  241. }
  242. /* Set global table */
  243. lua_setglobal (L, "rspamd_actions");
  244. }
  245. lua_State *
  246. rspamd_lua_init (struct rspamd_config *cfg)
  247. {
  248. lua_State *L;
  249. L = luaL_newstate ();
  250. luaL_openlibs (L);
  251. luaopen_logger (L);
  252. luaopen_mempool (L);
  253. luaopen_config (L);
  254. luaopen_radix (L);
  255. luaopen_hash_table (L);
  256. luaopen_trie (L);
  257. luaopen_task (L);
  258. luaopen_textpart (L);
  259. luaopen_mimepart (L);
  260. luaopen_image (L);
  261. luaopen_url (L);
  262. luaopen_message (L);
  263. luaopen_classifier (L);
  264. luaopen_statfile (L);
  265. luaopen_glib_regexp (L);
  266. luaopen_cdb (L);
  267. luaopen_xmlrpc (L);
  268. luaopen_http (L);
  269. luaopen_redis (L);
  270. luaopen_upstream (L);
  271. lua_add_actions_global (L);
  272. luaopen_session (L);
  273. luaopen_io_dispatcher (L);
  274. luaopen_dns_resolver (L);
  275. luaopen_rsa (L);
  276. luaopen_ip (L);
  277. rspamd_lua_add_preload (L, "ucl", luaopen_ucl);
  278. return L;
  279. }
  280. /**
  281. * Initialize new locked lua_State structure
  282. */
  283. struct lua_locked_state *
  284. rspamd_init_lua_locked (struct rspamd_config *cfg)
  285. {
  286. struct lua_locked_state *new;
  287. new = g_slice_alloc (sizeof (struct lua_locked_state));
  288. new->L = rspamd_lua_init (cfg);
  289. new->m = rspamd_mutex_new ();
  290. return new;
  291. }
  292. /**
  293. * Free locked state structure
  294. */
  295. void
  296. rspamd_free_lua_locked (struct lua_locked_state *st)
  297. {
  298. g_assert (st != NULL);
  299. lua_close (st->L);
  300. rspamd_mutex_free (st->m);
  301. g_slice_free1 (sizeof (struct lua_locked_state), st);
  302. }
  303. gboolean
  304. rspamd_init_lua_filters (struct rspamd_config *cfg)
  305. {
  306. struct rspamd_config **pcfg;
  307. GList *cur, *tmp;
  308. struct script_module *module;
  309. struct rspamd_statfile_config *st;
  310. lua_State *L = cfg->lua_state;
  311. cur = g_list_first (cfg->script_modules);
  312. while (cur) {
  313. module = cur->data;
  314. if (module->path) {
  315. if (luaL_loadfile (L, module->path) != 0) {
  316. msg_info ("load of %s failed: %s", module->path,
  317. lua_tostring (L, -1));
  318. cur = g_list_next (cur);
  319. return FALSE;
  320. }
  321. /* Initialize config structure */
  322. pcfg = lua_newuserdata (L, sizeof (struct rspamd_config *));
  323. rspamd_lua_setclass (L, "rspamd{config}", -1);
  324. *pcfg = cfg;
  325. lua_setglobal (L, "rspamd_config");
  326. /* do the call (0 arguments, N result) */
  327. if (lua_pcall (L, 0, LUA_MULTRET, 0) != 0) {
  328. msg_info ("init of %s failed: %s", module->path,
  329. lua_tostring (L, -1));
  330. return FALSE;
  331. }
  332. if (lua_gettop (L) != 0) {
  333. if (lua_tonumber (L, -1) == -1) {
  334. msg_info (
  335. "%s returned -1 that indicates configuration error",
  336. module->path);
  337. return FALSE;
  338. }
  339. lua_pop (L, lua_gettop (L));
  340. }
  341. }
  342. cur = g_list_next (cur);
  343. }
  344. /* Init statfiles normalizers */
  345. cur = g_list_first (cfg->statfiles);
  346. while (cur) {
  347. st = cur->data;
  348. if (st->normalizer == rspamd_lua_normalize) {
  349. tmp = st->normalizer_data;
  350. if (tmp && (tmp = g_list_next (tmp))) {
  351. if (tmp->data) {
  352. /* Code must be loaded from data */
  353. if (luaL_loadstring (L, tmp->data) != 0) {
  354. msg_info ("cannot load normalizer code %s", tmp->data);
  355. return FALSE;
  356. }
  357. }
  358. }
  359. }
  360. cur = g_list_next (cur);
  361. }
  362. /* Assign state */
  363. cfg->lua_state = L;
  364. return TRUE;
  365. }
  366. /* Callback functions */
  367. gint
  368. rspamd_lua_call_filter (const gchar *function, struct rspamd_task *task)
  369. {
  370. gint result;
  371. struct rspamd_task **ptask;
  372. lua_State *L = task->cfg->lua_state;
  373. lua_getglobal (L, function);
  374. ptask = lua_newuserdata (L, sizeof (struct rspamd_task *));
  375. rspamd_lua_setclass (L, "rspamd{task}", -1);
  376. *ptask = task;
  377. if (lua_pcall (L, 1, 1, 0) != 0) {
  378. msg_info ("call to %s failed", function);
  379. }
  380. /* retrieve result */
  381. if (!lua_isnumber (L, -1)) {
  382. msg_info ("function %s must return a number", function);
  383. }
  384. result = lua_tonumber (L, -1);
  385. lua_pop (L, 1); /* pop returned value */
  386. return result;
  387. }
  388. gint
  389. rspamd_lua_call_chain_filter (const gchar *function,
  390. struct rspamd_task *task,
  391. gint *marks,
  392. guint number)
  393. {
  394. gint result;
  395. guint i;
  396. lua_State *L = task->cfg->lua_state;
  397. lua_getglobal (L, function);
  398. for (i = 0; i < number; i++) {
  399. lua_pushnumber (L, marks[i]);
  400. }
  401. if (lua_pcall (L, number, 1, 0) != 0) {
  402. msg_info ("call to %s failed", function);
  403. }
  404. /* retrieve result */
  405. if (!lua_isnumber (L, -1)) {
  406. msg_info ("function %s must return a number", function);
  407. }
  408. result = lua_tonumber (L, -1);
  409. lua_pop (L, 1); /* pop returned value */
  410. return result;
  411. }
  412. /* Call custom lua function in rspamd expression */
  413. gboolean
  414. rspamd_lua_call_expression_func (gpointer lua_data,
  415. struct rspamd_task *task, GList *args, gboolean *res)
  416. {
  417. lua_State *L = task->cfg->lua_state;
  418. struct rspamd_task **ptask;
  419. GList *cur;
  420. struct expression_argument *arg;
  421. int nargs = 1, pop = 0;
  422. lua_rawgeti (L, LUA_REGISTRYINDEX, GPOINTER_TO_INT (lua_data));
  423. /* Now we got function in top of stack */
  424. ptask = lua_newuserdata (L, sizeof (struct rspamd_task *));
  425. rspamd_lua_setclass (L, "rspamd{task}", -1);
  426. *ptask = task;
  427. /* Now push all arguments */
  428. cur = args;
  429. while (cur) {
  430. arg = get_function_arg (cur->data, task, FALSE);
  431. if (arg) {
  432. switch (arg->type) {
  433. case EXPRESSION_ARGUMENT_NORMAL:
  434. lua_pushstring (L, (const gchar *)arg->data);
  435. break;
  436. case EXPRESSION_ARGUMENT_BOOL:
  437. lua_pushboolean (L, (gboolean) GPOINTER_TO_SIZE (arg->data));
  438. break;
  439. default:
  440. msg_err ("cannot pass custom params to lua function");
  441. return FALSE;
  442. }
  443. }
  444. nargs++;
  445. cur = g_list_next (cur);
  446. }
  447. if (lua_pcall (L, nargs, 1, 0) != 0) {
  448. msg_info ("call to lua function failed: %s", lua_tostring (L, -1));
  449. return FALSE;
  450. }
  451. pop++;
  452. if (!lua_isboolean (L, -1)) {
  453. lua_pop (L, pop);
  454. msg_info ("lua function must return a boolean");
  455. return FALSE;
  456. }
  457. *res = lua_toboolean (L, -1);
  458. lua_pop (L, pop);
  459. return TRUE;
  460. }
  461. /*
  462. * LUA custom consolidation function
  463. */
  464. struct consolidation_callback_data {
  465. struct rspamd_task *task;
  466. double score;
  467. const gchar *func;
  468. };
  469. static void
  470. lua_consolidation_callback (gpointer key, gpointer value, gpointer arg)
  471. {
  472. double res;
  473. struct symbol *s = (struct symbol *)value;
  474. struct consolidation_callback_data *data =
  475. (struct consolidation_callback_data *)arg;
  476. lua_State *L = data->task->cfg->lua_state;
  477. lua_getglobal (L, data->func);
  478. lua_pushstring (L, (const gchar *)key);
  479. lua_pushnumber (L, s->score);
  480. if (lua_pcall (L, 2, 1, 0) != 0) {
  481. msg_info ("call to %s failed", data->func);
  482. }
  483. /* retrieve result */
  484. if (!lua_isnumber (L, -1)) {
  485. msg_info ("function %s must return a number", data->func);
  486. }
  487. res = lua_tonumber (L, -1);
  488. lua_pop (L, 1); /* pop returned value */
  489. data->score += res;
  490. }
  491. double
  492. rspamd_lua_consolidation_func (struct rspamd_task *task,
  493. const gchar *metric_name,
  494. const gchar *function_name)
  495. {
  496. struct metric_result *metric_res;
  497. double res = 0.;
  498. struct consolidation_callback_data data = { task, 0, function_name };
  499. if (function_name == NULL) {
  500. return 0;
  501. }
  502. metric_res = g_hash_table_lookup (task->results, metric_name);
  503. if (metric_res == NULL) {
  504. return res;
  505. }
  506. g_hash_table_foreach (metric_res->symbols, lua_consolidation_callback,
  507. &data);
  508. return data.score;
  509. }
  510. double
  511. rspamd_lua_normalize (struct rspamd_config *cfg, long double score, void *params)
  512. {
  513. GList *p = params;
  514. long double res = score;
  515. lua_State *L = cfg->lua_state;
  516. /* Call specified function and put input score on stack */
  517. if (!p->data) {
  518. msg_info ("bad function name while calling normalizer");
  519. return score;
  520. }
  521. lua_getglobal (L, p->data);
  522. lua_pushnumber (L, score);
  523. if (lua_pcall (L, 1, 1, 0) != 0) {
  524. msg_info ("call to %s failed", p->data);
  525. }
  526. /* retrieve result */
  527. if (!lua_isnumber (L, -1)) {
  528. msg_info ("function %s must return a number", p->data);
  529. }
  530. res = lua_tonumber (L, -1);
  531. lua_pop (L, 1);
  532. return res;
  533. }
  534. void
  535. rspamd_lua_dumpstack (lua_State *L)
  536. {
  537. gint i, t, r = 0;
  538. gint top = lua_gettop (L);
  539. gchar buf[BUFSIZ];
  540. r += rspamd_snprintf (buf + r, sizeof (buf) - r, "lua stack: ");
  541. for (i = 1; i <= top; i++) { /* repeat for each level */
  542. t = lua_type (L, i);
  543. switch (t)
  544. {
  545. case LUA_TSTRING: /* strings */
  546. r += rspamd_snprintf (buf + r,
  547. sizeof (buf) - r,
  548. "str: %s",
  549. lua_tostring (L, i));
  550. break;
  551. case LUA_TBOOLEAN: /* booleans */
  552. r += rspamd_snprintf (buf + r, sizeof (buf) - r,lua_toboolean (L,
  553. i) ? "bool: true" : "bool: false");
  554. break;
  555. case LUA_TNUMBER: /* numbers */
  556. r += rspamd_snprintf (buf + r,
  557. sizeof (buf) - r,
  558. "number: %.2f",
  559. lua_tonumber (L, i));
  560. break;
  561. default: /* other values */
  562. r += rspamd_snprintf (buf + r,
  563. sizeof (buf) - r,
  564. "type: %s",
  565. lua_typename (L, t));
  566. break;
  567. }
  568. if (i < top) {
  569. r += rspamd_snprintf (buf + r, sizeof (buf) - r, " -> "); /* put a separator */
  570. }
  571. }
  572. msg_info (buf);
  573. }
  574. gpointer
  575. rspamd_lua_check_class (lua_State *L, gint index, const gchar *name)
  576. {
  577. gpointer p;
  578. if (lua_type (L, index) == LUA_TUSERDATA) {
  579. p = lua_touserdata (L, index);
  580. if (p) {
  581. if (lua_getmetatable (L, index)) {
  582. lua_getfield (L, LUA_REGISTRYINDEX, name); /* get correct metatable */
  583. if (lua_rawequal (L, -1, -2)) { /* does it have the correct mt? */
  584. lua_pop (L, 2); /* remove both metatables */
  585. return p;
  586. }
  587. lua_pop (L, 2);
  588. }
  589. }
  590. }
  591. return NULL;
  592. }
  593. int
  594. rspamd_lua_typerror (lua_State *L, int narg, const char *tname)
  595. {
  596. const char *msg = lua_pushfstring (L, "%s expected, got %s", tname,
  597. luaL_typename (L, narg));
  598. return luaL_argerror (L, narg, msg);
  599. }
  600. void
  601. rspamd_lua_add_preload (lua_State *L, const gchar *name, lua_CFunction func)
  602. {
  603. lua_getglobal (L, "package");
  604. lua_pushstring (L, "preload");
  605. lua_gettable (L, -2);
  606. lua_pushcfunction (L, func);
  607. lua_setfield (L, -2, name);
  608. lua_pop (L, 1);
  609. }