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_text.c 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /*-
  2. * Copyright 2019 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 "libcryptobox/cryptobox.h"
  18. #include "unix-std.h"
  19. /***
  20. * @module rspamd_text
  21. * This module provides access to opaque text structures used widely to prevent
  22. * copying between Lua and C for various concerns: performance, security etc...
  23. *
  24. * You can convert rspamd_text into string but it will copy data.
  25. */
  26. /**
  27. * @function rspamd_text.fromstring(str)
  28. * Creates rspamd_text from Lua string (copied to the text)
  29. * @param {string} str string to use
  30. * @return {rspamd_text} resulting text
  31. */
  32. LUA_FUNCTION_DEF (text, fromstring);
  33. /**
  34. * @function rspamd_text.fromtable(tbl[, delim])
  35. * Same as `table.concat` but generates rspamd_text instead of the Lua string
  36. * @param {table} tbl table to use
  37. * @param {string} delim optional delimiter
  38. * @return {rspamd_text} resulting text
  39. */
  40. LUA_FUNCTION_DEF (text, fromtable);
  41. /***
  42. * @method rspamd_text:len()
  43. * Returns length of a string
  44. * @return {number} length of string in **bytes**
  45. */
  46. LUA_FUNCTION_DEF (text, len);
  47. /***
  48. * @method rspamd_text:str()
  49. * Converts text to string by copying its content
  50. * @return {string} copy of text as Lua string
  51. */
  52. LUA_FUNCTION_DEF (text, str);
  53. /***
  54. * @method rspamd_text:ptr()
  55. * Converts text to lightuserdata
  56. * @return {lightuserdata} pointer value of rspamd_text
  57. */
  58. LUA_FUNCTION_DEF (text, ptr);
  59. /***
  60. * @method rspamd_text:save_in_file(fname[, mode])
  61. * Saves text in file
  62. * @return {boolean} true if save has been completed
  63. */
  64. LUA_FUNCTION_DEF (text, save_in_file);
  65. LUA_FUNCTION_DEF (text, take_ownership);
  66. LUA_FUNCTION_DEF (text, gc);
  67. LUA_FUNCTION_DEF (text, eq);
  68. static const struct luaL_reg textlib_f[] = {
  69. LUA_INTERFACE_DEF (text, fromstring),
  70. LUA_INTERFACE_DEF (text, fromtable),
  71. {NULL, NULL}
  72. };
  73. static const struct luaL_reg textlib_m[] = {
  74. LUA_INTERFACE_DEF (text, len),
  75. LUA_INTERFACE_DEF (text, str),
  76. LUA_INTERFACE_DEF (text, ptr),
  77. LUA_INTERFACE_DEF (text, take_ownership),
  78. LUA_INTERFACE_DEF (text, save_in_file),
  79. {"write", lua_text_save_in_file},
  80. {"__len", lua_text_len},
  81. {"__tostring", lua_text_str},
  82. {"__gc", lua_text_gc},
  83. {"__eq", lua_text_eq},
  84. {NULL, NULL}
  85. };
  86. static gint
  87. lua_text_fromstring (lua_State *L)
  88. {
  89. LUA_TRACE_POINT;
  90. const gchar *str;
  91. gsize l = 0;
  92. struct rspamd_lua_text *t;
  93. str = luaL_checklstring (L, 1, &l);
  94. if (str) {
  95. t = lua_newuserdata (L, sizeof (*t));
  96. t->start = g_malloc (l + 1);
  97. rspamd_strlcpy ((char *)t->start, str, l + 1);
  98. t->len = l;
  99. t->flags = RSPAMD_TEXT_FLAG_OWN;
  100. rspamd_lua_setclass (L, "rspamd{text}", -1);
  101. }
  102. else {
  103. return luaL_error (L, "invalid arguments");
  104. }
  105. return 1;
  106. }
  107. static gint
  108. lua_text_fromtable (lua_State *L)
  109. {
  110. LUA_TRACE_POINT;
  111. const gchar *delim = "", *st;
  112. struct rspamd_lua_text *t, *elt;
  113. gsize textlen = 0, dlen, stlen, tblen;
  114. gchar *dest;
  115. if (!lua_istable (L, 1)) {
  116. return luaL_error (L, "invalid arguments");
  117. }
  118. if (lua_type (L, 2) == LUA_TSTRING) {
  119. delim = lua_tolstring (L, 2, &dlen);
  120. }
  121. else {
  122. dlen = strlen (delim);
  123. }
  124. /* Calculate length needed */
  125. tblen = rspamd_lua_table_size (L, 1);
  126. for (guint i = 0; i < tblen; i ++) {
  127. lua_rawgeti (L, 1, i + 1);
  128. if (lua_type (L, -1) == LUA_TSTRING) {
  129. #if LUA_VERSION_NUM >= 502
  130. stlen = lua_rawlen (L, -1);
  131. #else
  132. stlen = lua_objlen (L, -1);
  133. #endif
  134. textlen += stlen;
  135. }
  136. else {
  137. elt = lua_check_text (L, -1);
  138. if (elt) {
  139. textlen += elt->len;
  140. }
  141. }
  142. lua_pop (L, 1);
  143. textlen += dlen;
  144. }
  145. /* Allocate new text */
  146. t = lua_newuserdata (L, sizeof (*t));
  147. dest = g_malloc (textlen);
  148. t->start = dest;
  149. t->len = textlen;
  150. t->flags = RSPAMD_TEXT_FLAG_OWN;
  151. rspamd_lua_setclass (L, "rspamd{text}", -1);
  152. for (guint i = 0; i < tblen; i ++) {
  153. lua_rawgeti (L, 1, i + 1);
  154. if (lua_type (L, -1) == LUA_TSTRING) {
  155. st = lua_tolstring (L, -1, &stlen);
  156. memcpy (dest, st, stlen);
  157. dest += stlen;
  158. }
  159. else {
  160. elt = lua_check_text (L, -1);
  161. if (elt) {
  162. memcpy (dest, elt->start, elt->len);
  163. }
  164. }
  165. memcpy (dest, delim, dlen);
  166. lua_pop (L, 1);
  167. }
  168. return 1;
  169. }
  170. static gint
  171. lua_text_len (lua_State *L)
  172. {
  173. LUA_TRACE_POINT;
  174. struct rspamd_lua_text *t = lua_check_text (L, 1);
  175. gsize l = 0;
  176. if (t != NULL) {
  177. l = t->len;
  178. }
  179. else {
  180. return luaL_error (L, "invalid arguments");
  181. }
  182. lua_pushinteger (L, l);
  183. return 1;
  184. }
  185. static gint
  186. lua_text_str (lua_State *L)
  187. {
  188. LUA_TRACE_POINT;
  189. struct rspamd_lua_text *t = lua_check_text (L, 1);
  190. if (t != NULL) {
  191. lua_pushlstring (L, t->start, t->len);
  192. }
  193. else {
  194. return luaL_error (L, "invalid arguments");
  195. }
  196. return 1;
  197. }
  198. static gint
  199. lua_text_ptr (lua_State *L)
  200. {
  201. LUA_TRACE_POINT;
  202. struct rspamd_lua_text *t = lua_check_text (L, 1);
  203. if (t != NULL) {
  204. lua_pushlightuserdata (L, (gpointer)t->start);
  205. }
  206. else {
  207. return luaL_error (L, "invalid arguments");
  208. }
  209. return 1;
  210. }
  211. static gint
  212. lua_text_take_ownership (lua_State *L)
  213. {
  214. LUA_TRACE_POINT;
  215. struct rspamd_lua_text *t = lua_check_text (L, 1);
  216. gchar *dest;
  217. if (t != NULL) {
  218. if (t->flags & RSPAMD_TEXT_FLAG_OWN) {
  219. /* We already own it */
  220. lua_pushboolean (L, true);
  221. }
  222. else {
  223. dest = g_malloc (t->len);
  224. memcpy (dest, t->start, t->len);
  225. t->start = dest;
  226. t->flags |= RSPAMD_TEXT_FLAG_OWN;
  227. lua_pushboolean (L, true);
  228. }
  229. }
  230. else {
  231. return luaL_error (L, "invalid arguments");
  232. }
  233. return 1;
  234. }
  235. static gint
  236. lua_text_save_in_file (lua_State *L)
  237. {
  238. LUA_TRACE_POINT;
  239. struct rspamd_lua_text *t = lua_check_text (L, 1);
  240. const gchar *fname = NULL;
  241. guint mode = 00644;
  242. gint fd = -1;
  243. gboolean need_close = FALSE;
  244. if (t != NULL) {
  245. if (lua_type (L, 2) == LUA_TSTRING) {
  246. fname = luaL_checkstring (L, 2);
  247. if (lua_type (L, 3) == LUA_TNUMBER) {
  248. mode = lua_tonumber (L, 3);
  249. }
  250. }
  251. else if (lua_type (L, 2) == LUA_TNUMBER) {
  252. /* Created fd */
  253. fd = lua_tonumber (L, 2);
  254. }
  255. if (fd == -1) {
  256. if (fname) {
  257. fd = rspamd_file_xopen (fname, O_CREAT | O_WRONLY | O_EXCL, mode, 0);
  258. if (fd == -1) {
  259. lua_pushboolean (L, false);
  260. lua_pushstring (L, strerror (errno));
  261. return 2;
  262. }
  263. need_close = TRUE;
  264. }
  265. else {
  266. fd = STDOUT_FILENO;
  267. }
  268. }
  269. if (write (fd, t->start, t->len) == -1) {
  270. if (fd != STDOUT_FILENO) {
  271. close (fd);
  272. }
  273. lua_pushboolean (L, false);
  274. lua_pushstring (L, strerror (errno));
  275. return 2;
  276. }
  277. if (need_close) {
  278. close (fd);
  279. }
  280. lua_pushboolean (L, true);
  281. }
  282. else {
  283. return luaL_error (L, "invalid arguments");
  284. }
  285. return 1;
  286. }
  287. static gint
  288. lua_text_gc (lua_State *L)
  289. {
  290. LUA_TRACE_POINT;
  291. struct rspamd_lua_text *t = lua_check_text (L, 1);
  292. if (t != NULL) {
  293. if (t->flags & RSPAMD_TEXT_FLAG_OWN) {
  294. if (t->flags & RSPAMD_TEXT_FLAG_WIPE) {
  295. rspamd_explicit_memzero ((guchar *)t->start, t->len);
  296. }
  297. if (t->flags & RSPAMD_TEXT_FLAG_MMAPED) {
  298. munmap ((gpointer)t->start, t->len);
  299. }
  300. else {
  301. g_free ((gpointer)t->start);
  302. }
  303. }
  304. }
  305. return 0;
  306. }
  307. static gint
  308. lua_text_eq (lua_State *L)
  309. {
  310. LUA_TRACE_POINT;
  311. struct rspamd_lua_text *t1 = lua_check_text (L, 1),
  312. *t2 = lua_check_text (L, 2);
  313. if (t1->len == t2->len) {
  314. lua_pushboolean (L, memcmp (t1->start, t2->start, t1->len) == 0);
  315. }
  316. else {
  317. lua_pushboolean (L, false);
  318. }
  319. return 1;
  320. }
  321. static gint
  322. lua_text_wipe (lua_State *L)
  323. {
  324. LUA_TRACE_POINT;
  325. struct rspamd_lua_text *t = lua_check_text (L, 1);
  326. if (t != NULL) {
  327. if (t->flags & RSPAMD_TEXT_FLAG_OWN) {
  328. rspamd_explicit_memzero ((guchar *)t->start, t->len);
  329. }
  330. else {
  331. return luaL_error (L, "cannot wipe not owned text");
  332. }
  333. }
  334. else {
  335. return luaL_error (L, "invalid arguments");
  336. }
  337. return 0;
  338. }
  339. static gint
  340. lua_load_text (lua_State * L)
  341. {
  342. lua_newtable (L);
  343. luaL_register (L, NULL, textlib_f);
  344. return 1;
  345. }
  346. void
  347. luaopen_text (lua_State *L)
  348. {
  349. rspamd_lua_new_class (L, "rspamd{text}", textlib_m);
  350. lua_pop (L, 1);
  351. rspamd_lua_add_preload (L, "rspamd_text", lua_load_text);
  352. }