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_xmlrpc.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. /* Copyright (c) 2010, Vsevolod Stakhov
  2. * All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. * * Redistributions of source code must retain the above copyright
  7. * notice, this list of conditions and the following disclaimer.
  8. * * Redistributions in binary form must reproduce the above copyright
  9. * notice, this list of conditions and the following disclaimer in the
  10. * documentation and/or other materials provided with the distribution.
  11. *
  12. * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
  13. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  16. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #include "lua_common.h"
  24. LUA_FUNCTION_DEF (xmlrpc, parse_reply);
  25. LUA_FUNCTION_DEF (xmlrpc, make_request);
  26. static const struct luaL_reg xmlrpclib_m[] = {
  27. LUA_INTERFACE_DEF (xmlrpc, parse_reply),
  28. LUA_INTERFACE_DEF (xmlrpc, make_request),
  29. {"__tostring", rspamd_lua_class_tostring},
  30. {NULL, NULL}
  31. };
  32. struct lua_xmlrpc_ud {
  33. gint parser_state;
  34. gint depth;
  35. gint param_count;
  36. gboolean got_text;
  37. lua_State *L;
  38. };
  39. static void xmlrpc_start_element (GMarkupParseContext *context,
  40. const gchar *name,
  41. const gchar **attribute_names,
  42. const gchar **attribute_values,
  43. gpointer user_data,
  44. GError **error);
  45. static void xmlrpc_end_element (GMarkupParseContext *context,
  46. const gchar *element_name,
  47. gpointer user_data,
  48. GError **error);
  49. static void xmlrpc_error (GMarkupParseContext *context,
  50. GError *error,
  51. gpointer user_data);
  52. static void xmlrpc_text (GMarkupParseContext *context,
  53. const gchar *text,
  54. gsize text_len,
  55. gpointer user_data,
  56. GError **error);
  57. static GMarkupParser xmlrpc_parser = {
  58. .start_element = xmlrpc_start_element,
  59. .end_element = xmlrpc_end_element,
  60. .passthrough = NULL,
  61. .text = xmlrpc_text,
  62. .error = xmlrpc_error,
  63. };
  64. static GQuark
  65. xmlrpc_error_quark (void)
  66. {
  67. return g_quark_from_static_string ("xmlrpc-error-quark");
  68. }
  69. static void
  70. xmlrpc_start_element (GMarkupParseContext *context,
  71. const gchar *name,
  72. const gchar **attribute_names,
  73. const gchar **attribute_values,
  74. gpointer user_data,
  75. GError **error)
  76. {
  77. struct lua_xmlrpc_ud *ud = user_data;
  78. int last_state;
  79. last_state = ud->parser_state;
  80. switch (ud->parser_state) {
  81. case 0:
  82. /* Expect tag methodResponse */
  83. if (g_ascii_strcasecmp (name, "methodResponse") == 0) {
  84. ud->parser_state = 1;
  85. }
  86. else {
  87. /* Error state */
  88. ud->parser_state = 99;
  89. }
  90. break;
  91. case 1:
  92. /* Expect tag params */
  93. if (g_ascii_strcasecmp (name, "params") == 0) {
  94. ud->parser_state = 2;
  95. /* result -> table of params indexed by int */
  96. lua_newtable (ud->L);
  97. }
  98. else {
  99. /* Error state */
  100. ud->parser_state = 99;
  101. }
  102. break;
  103. case 2:
  104. /* Expect tag param */
  105. if (g_ascii_strcasecmp (name, "param") == 0) {
  106. ud->parser_state = 3;
  107. /* Create new param */
  108. }
  109. else {
  110. /* Error state */
  111. ud->parser_state = 99;
  112. }
  113. break;
  114. case 3:
  115. /* Expect tag value */
  116. if (g_ascii_strcasecmp (name, "value") == 0) {
  117. ud->parser_state = 4;
  118. }
  119. else {
  120. /* Error state */
  121. ud->parser_state = 99;
  122. }
  123. break;
  124. case 4:
  125. /* Expect tag struct */
  126. if (g_ascii_strcasecmp (name, "struct") == 0) {
  127. ud->parser_state = 5;
  128. /* Create new param of table type */
  129. lua_newtable (ud->L);
  130. ud->depth++;
  131. }
  132. else if (g_ascii_strcasecmp (name, "string") == 0) {
  133. ud->parser_state = 11;
  134. ud->got_text = FALSE;
  135. }
  136. else if (g_ascii_strcasecmp (name, "int") == 0) {
  137. ud->parser_state = 12;
  138. ud->got_text = FALSE;
  139. }
  140. else if (g_ascii_strcasecmp (name, "double") == 0) {
  141. ud->parser_state = 13;
  142. ud->got_text = FALSE;
  143. }
  144. else {
  145. /* Error state */
  146. ud->parser_state = 99;
  147. }
  148. break;
  149. case 5:
  150. /* Parse structure */
  151. /* Expect tag member */
  152. if (g_ascii_strcasecmp (name, "member") == 0) {
  153. ud->parser_state = 6;
  154. }
  155. else {
  156. /* Error state */
  157. ud->parser_state = 99;
  158. }
  159. break;
  160. case 6:
  161. /* Expect tag name */
  162. if (g_ascii_strcasecmp (name, "name") == 0) {
  163. ud->parser_state = 7;
  164. }
  165. else {
  166. /* Error state */
  167. ud->parser_state = 99;
  168. }
  169. break;
  170. case 7:
  171. /* Accept value */
  172. if (g_ascii_strcasecmp (name, "value") == 0) {
  173. ud->parser_state = 8;
  174. }
  175. else {
  176. /* Error state */
  177. ud->parser_state = 99;
  178. }
  179. break;
  180. case 8:
  181. /* Parse any values */
  182. /* Primitives */
  183. if (g_ascii_strcasecmp (name, "string") == 0) {
  184. ud->parser_state = 11;
  185. ud->got_text = FALSE;
  186. }
  187. else if (g_ascii_strcasecmp (name, "int") == 0) {
  188. ud->parser_state = 12;
  189. ud->got_text = FALSE;
  190. }
  191. else if (g_ascii_strcasecmp (name, "double") == 0) {
  192. ud->parser_state = 13;
  193. ud->got_text = FALSE;
  194. }
  195. /* Structure */
  196. else if (g_ascii_strcasecmp (name, "struct") == 0) {
  197. ud->parser_state = 5;
  198. /* Create new param of table type */
  199. lua_newtable (ud->L);
  200. ud->depth++;
  201. }
  202. else {
  203. /* Error state */
  204. ud->parser_state = 99;
  205. }
  206. break;
  207. }
  208. if (ud->parser_state == 99) {
  209. g_set_error (error,
  210. xmlrpc_error_quark (), 1, "xmlrpc parse error on state: %d, while parsing start tag: %s",
  211. last_state, name);
  212. }
  213. }
  214. static void
  215. xmlrpc_end_element (GMarkupParseContext *context,
  216. const gchar *name,
  217. gpointer user_data,
  218. GError **error)
  219. {
  220. struct lua_xmlrpc_ud *ud = user_data;
  221. int last_state;
  222. last_state = ud->parser_state;
  223. switch (ud->parser_state) {
  224. case 0:
  225. ud->parser_state = 99;
  226. break;
  227. case 1:
  228. /* Got methodResponse */
  229. if (g_ascii_strcasecmp (name, "methodResponse") == 0) {
  230. /* End processing */
  231. ud->parser_state = 100;
  232. }
  233. else {
  234. /* Error state */
  235. ud->parser_state = 99;
  236. }
  237. break;
  238. case 2:
  239. /* Got tag params */
  240. if (g_ascii_strcasecmp (name, "params") == 0) {
  241. ud->parser_state = 1;
  242. }
  243. else {
  244. /* Error state */
  245. ud->parser_state = 99;
  246. }
  247. break;
  248. case 3:
  249. /* Got tag param */
  250. if (g_ascii_strcasecmp (name, "param") == 0) {
  251. ud->parser_state = 2;
  252. lua_rawseti (ud->L, -2, ++ud->param_count);
  253. }
  254. else {
  255. /* Error state */
  256. ud->parser_state = 99;
  257. }
  258. break;
  259. case 4:
  260. /* Got tag value */
  261. if (g_ascii_strcasecmp (name, "value") == 0) {
  262. if (ud->depth == 0) {
  263. ud->parser_state = 3;
  264. }
  265. else {
  266. /* Parse other members */
  267. ud->parser_state = 6;
  268. }
  269. }
  270. else {
  271. /* Error state */
  272. ud->parser_state = 99;
  273. }
  274. break;
  275. case 5:
  276. /* Got tag struct */
  277. if (g_ascii_strcasecmp (name, "struct") == 0) {
  278. ud->parser_state = 4;
  279. ud->depth--;
  280. }
  281. else {
  282. /* Error state */
  283. ud->parser_state = 99;
  284. }
  285. break;
  286. case 6:
  287. /* Got tag member */
  288. if (g_ascii_strcasecmp (name, "member") == 0) {
  289. ud->parser_state = 5;
  290. /* Set table */
  291. lua_settable (ud->L, -3);
  292. }
  293. else {
  294. /* Error state */
  295. ud->parser_state = 99;
  296. }
  297. break;
  298. case 7:
  299. /* Got tag name */
  300. if (g_ascii_strcasecmp (name, "name") == 0) {
  301. ud->parser_state = 7;
  302. }
  303. else {
  304. /* Error state */
  305. ud->parser_state = 99;
  306. }
  307. break;
  308. case 8:
  309. /* Got tag value */
  310. if (g_ascii_strcasecmp (name, "value") == 0) {
  311. ud->parser_state = 6;
  312. }
  313. else {
  314. /* Error state */
  315. ud->parser_state = 99;
  316. }
  317. break;
  318. case 11:
  319. case 12:
  320. case 13:
  321. /* Parse any values */
  322. /* Handle empty tags */
  323. if (!ud->got_text) {
  324. lua_pushnil (ud->L);
  325. }
  326. else {
  327. ud->got_text = FALSE;
  328. }
  329. /* Primitives */
  330. if (g_ascii_strcasecmp (name, "string") == 0) {
  331. ud->parser_state = 8;
  332. }
  333. else if (g_ascii_strcasecmp (name, "int") == 0) {
  334. ud->parser_state = 8;
  335. }
  336. else if (g_ascii_strcasecmp (name, "double") == 0) {
  337. ud->parser_state = 8;
  338. }
  339. else {
  340. /* Error state */
  341. ud->parser_state = 99;
  342. }
  343. break;
  344. }
  345. if (ud->parser_state == 99) {
  346. g_set_error (error,
  347. xmlrpc_error_quark (), 1, "xmlrpc parse error on state: %d, while parsing end tag: %s",
  348. last_state, name);
  349. }
  350. }
  351. static void
  352. xmlrpc_text (GMarkupParseContext *context,
  353. const gchar *text,
  354. gsize text_len,
  355. gpointer user_data,
  356. GError **error)
  357. {
  358. struct lua_xmlrpc_ud *ud = user_data;
  359. gint num;
  360. gdouble dnum;
  361. /* Strip line */
  362. while (text_len > 0 && g_ascii_isspace (*text)) {
  363. text++;
  364. text_len--;
  365. }
  366. while (text_len > 0 && g_ascii_isspace (text[text_len - 1])) {
  367. text_len--;
  368. }
  369. if (text_len > 0) {
  370. switch (ud->parser_state) {
  371. case 7:
  372. /* Push key */
  373. lua_pushlstring (ud->L, text, text_len);
  374. break;
  375. case 11:
  376. /* Push string value */
  377. lua_pushlstring (ud->L, text, text_len);
  378. break;
  379. case 12:
  380. /* Push integer value */
  381. num = strtoul (text, NULL, 10);
  382. lua_pushinteger (ud->L, num);
  383. break;
  384. case 13:
  385. /* Push integer value */
  386. dnum = strtod (text, NULL);
  387. lua_pushnumber (ud->L, dnum);
  388. break;
  389. }
  390. ud->got_text = TRUE;
  391. }
  392. }
  393. static void
  394. xmlrpc_error (GMarkupParseContext *context, GError *error, gpointer user_data)
  395. {
  396. struct lua_xmlrpc_ud *ud = user_data;
  397. msg_err ("xmlrpc parser error: %s", error->message, ud->parser_state);
  398. }
  399. static gint
  400. lua_xmlrpc_parse_reply (lua_State *L)
  401. {
  402. const gchar *data;
  403. GMarkupParseContext *ctx;
  404. GError *err = NULL;
  405. struct lua_xmlrpc_ud ud;
  406. gsize s;
  407. gboolean res;
  408. data = luaL_checklstring (L, 1, &s);
  409. if (data != NULL) {
  410. ud.L = L;
  411. ud.parser_state = 0;
  412. ud.depth = 0;
  413. ud.param_count = 0;
  414. ctx = g_markup_parse_context_new (&xmlrpc_parser,
  415. G_MARKUP_TREAT_CDATA_AS_TEXT, &ud, NULL);
  416. res = g_markup_parse_context_parse (ctx, data, s, &err);
  417. g_markup_parse_context_free (ctx);
  418. if (!res) {
  419. lua_pushnil (L);
  420. }
  421. }
  422. else {
  423. lua_pushnil (L);
  424. }
  425. /* Return table or nil */
  426. return 1;
  427. }
  428. static gint
  429. lua_xmlrpc_parse_table (lua_State *L,
  430. gint pos,
  431. gchar *databuf,
  432. gint pr,
  433. gsize size)
  434. {
  435. gint r = pr, num;
  436. double dnum;
  437. r += rspamd_snprintf (databuf + r, size - r, "<struct>");
  438. lua_pushnil (L); /* first key */
  439. while (lua_next (L, pos) != 0) {
  440. /* uses 'key' (at index -2) and 'value' (at index -1) */
  441. if (lua_type (L, -2) != LUA_TSTRING) {
  442. /* Ignore non sting keys */
  443. lua_pop (L, 1);
  444. continue;
  445. }
  446. r += rspamd_snprintf (databuf + r,
  447. size - r,
  448. "<member><name>%s</name><value>",
  449. lua_tostring (L, -2));
  450. switch (lua_type (L, -1)) {
  451. case LUA_TNUMBER:
  452. num = lua_tointeger (L, -1);
  453. dnum = lua_tonumber (L, -1);
  454. /* Try to avoid conversion errors */
  455. if (dnum != (double)num) {
  456. r += rspamd_snprintf (databuf + r,
  457. sizeof (databuf) - r,
  458. "<double>%f</double>",
  459. dnum);
  460. }
  461. else {
  462. r += rspamd_snprintf (databuf + r,
  463. sizeof (databuf) - r,
  464. "<int>%d</int>",
  465. num);
  466. }
  467. break;
  468. case LUA_TBOOLEAN:
  469. r += rspamd_snprintf (databuf + r,
  470. size - r,
  471. "<boolean>%d</boolean>",
  472. lua_toboolean (L, -1) ? 1 : 0);
  473. break;
  474. case LUA_TSTRING:
  475. r += rspamd_snprintf (databuf + r, size - r, "<string>%s</string>",
  476. lua_tostring (L, -1));
  477. break;
  478. case LUA_TTABLE:
  479. /* Recursive call */
  480. r += lua_xmlrpc_parse_table (L, -1, databuf + r, r, size);
  481. break;
  482. }
  483. r += rspamd_snprintf (databuf + r, size - r, "</value></member>");
  484. /* removes 'value'; keeps 'key' for next iteration */
  485. lua_pop (L, 1);
  486. }
  487. r += rspamd_snprintf (databuf + r, size - r, "</struct>");
  488. return r - pr;
  489. }
  490. /*
  491. * Internal limitation: xmlrpc request must NOT be more than
  492. * BUFSIZ * 2 (16384 bytes)
  493. */
  494. static gint
  495. lua_xmlrpc_make_request (lua_State *L)
  496. {
  497. gchar databuf[BUFSIZ * 2];
  498. const gchar *func;
  499. gint r, top, i, num;
  500. double dnum;
  501. func = luaL_checkstring (L, 1);
  502. if (func) {
  503. r = rspamd_snprintf (databuf, sizeof(databuf),
  504. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  505. "<methodCall><methodName>%s</methodName><params>",
  506. func);
  507. /* Extract arguments */
  508. top = lua_gettop (L);
  509. /* Get additional options */
  510. for (i = 2; i <= top; i++) {
  511. r += rspamd_snprintf (databuf + r,
  512. sizeof (databuf) - r,
  513. "<param><value>");
  514. switch (lua_type (L, i)) {
  515. case LUA_TNUMBER:
  516. num = lua_tointeger (L, i);
  517. dnum = lua_tonumber (L, i);
  518. /* Try to avoid conversion errors */
  519. if (dnum != (double)num) {
  520. r += rspamd_snprintf (databuf + r,
  521. sizeof (databuf) - r,
  522. "<double>%f</double>",
  523. dnum);
  524. }
  525. else {
  526. r += rspamd_snprintf (databuf + r,
  527. sizeof (databuf) - r,
  528. "<int>%d</int>",
  529. num);
  530. }
  531. break;
  532. case LUA_TBOOLEAN:
  533. r += rspamd_snprintf (databuf + r,
  534. sizeof (databuf) - r,
  535. "<boolean>%d</boolean>",
  536. lua_toboolean (L, i) ? 1 : 0);
  537. break;
  538. case LUA_TSTRING:
  539. r += rspamd_snprintf (databuf + r,
  540. sizeof (databuf) - r,
  541. "<string>%s</string>",
  542. lua_tostring (L, i));
  543. break;
  544. case LUA_TTABLE:
  545. r +=
  546. lua_xmlrpc_parse_table (L, i, databuf, r, sizeof (databuf));
  547. break;
  548. }
  549. r += rspamd_snprintf (databuf + r,
  550. sizeof (databuf) - r,
  551. "</value></param>");
  552. }
  553. r += rspamd_snprintf (databuf + r,
  554. sizeof (databuf) - r,
  555. "</params></methodCall>");
  556. lua_pushlstring (L, databuf, r);
  557. }
  558. else {
  559. lua_pushnil (L);
  560. }
  561. return 1;
  562. }
  563. static gint
  564. lua_load_xmlrpc (lua_State * L)
  565. {
  566. lua_newtable (L);
  567. luaL_register (L, NULL, xmlrpclib_m);
  568. return 1;
  569. }
  570. void
  571. luaopen_xmlrpc (lua_State * L)
  572. {
  573. rspamd_lua_add_preload (L, "rspamd_xmlrpc", lua_load_xmlrpc);
  574. }