static gboolean lua_tcp_arg_toiovec (lua_State *L, gint pos, rspamd_mempool_t *pool, struct iovec *vec) { struct rspamd_lua_text *t; gsize len; const gchar *str; if (lua_type (L, pos) == LUA_TUSERDATA) { t = lua_check_text (L, pos); if (t) { vec->iov_base = (void *)t->start; vec->iov_len = t->len; } else { return FALSE; } } else if (lua_type (L, pos) == LUA_TSTRING) { str = luaL_checklstring (L, pos, &len); vec->iov_base = rspamd_mempool_alloc (pool, len + 1); rspamd_strlcpy (vec->iov_base, str, len + 1); vec->iov_len = len; } else { return FALSE; } return TRUE; }
/*** * @function rspamd_cryptobox_hash.create([string]) * Creates new hash context * @param {string} data optional string to hash * @return {cryptobox_hash} hash object */ static gint lua_cryptobox_hash_create (lua_State *L) { struct rspamd_lua_cryptobox_hash *h, **ph; const gchar *s = NULL; struct rspamd_lua_text *t; gsize len = 0; h = rspamd_lua_hash_create (NULL); if (lua_type (L, 1) == LUA_TSTRING) { s = lua_tolstring (L, 1, &len); } else if (lua_type (L, 1) == LUA_TUSERDATA) { t = lua_check_text (L, 1); if (!t) { return luaL_error (L, "invalid arguments"); } s = t->start; len = t->len; } if (s) { rspamd_lua_hash_update (h, s, len); } ph = lua_newuserdata (L, sizeof (void *)); *ph = h; rspamd_lua_setclass (L, "rspamd{cryptobox_hash}", -1); return 1; }
/*** * @function rspamd_fann.load_data(data) * Loads neural network from the data * @param {string} file filename where fann is stored * @return {fann} fann object */ static gint lua_fann_load_data (lua_State *L) { #ifndef WITH_FANN return 0; #else struct fann *f, **pfann; gint fd; struct rspamd_lua_text *t; gchar fpath[PATH_MAX]; if (lua_type (L, 1) == LUA_TUSERDATA) { t = lua_check_text (L, 1); if (!t) { return luaL_error (L, "text required"); } } else { t = g_alloca (sizeof (*t)); t->start = lua_tolstring (L, 1, (gsize *)&t->len); t->flags = 0; } /* We need to save data to file because of libfann stupidity */ rspamd_strlcpy (fpath, "/tmp/rspamd-fannXXXXXXXXXX", sizeof (fpath)); fd = mkstemp (fpath); if (fd == -1) { msg_warn ("cannot create tempfile: %s", strerror (errno)); lua_pushnil (L); } else { if (write (fd, t->start, t->len) == -1) { msg_warn ("cannot write tempfile: %s", strerror (errno)); lua_pushnil (L); unlink (fpath); close (fd); return 1; } f = fann_create_from_file (fpath); unlink (fpath); close (fd); if (f != NULL) { pfann = lua_newuserdata (L, sizeof (gpointer)); *pfann = f; rspamd_lua_setclass (L, "rspamd{fann}", -1); } else { lua_pushnil (L); } } return 1; #endif }
static gint lua_util_decode_base64 (lua_State *L) { struct rspamd_lua_text *t; const gchar *s = NULL; gsize inlen, outlen; gboolean zero_copy = FALSE, grab_own = FALSE; gint state = 0; guint save = 0; if (lua_type (L, 1) == LUA_TSTRING) { s = luaL_checklstring (L, 1, &inlen); } else if (lua_type (L, 1) == LUA_TUSERDATA) { t = lua_check_text (L, 1); if (t != NULL) { s = t->start; inlen = t->len; zero_copy = TRUE; if (t->own) { t->own = FALSE; grab_own = TRUE; } } } if (s != NULL) { if (zero_copy) { /* Decode in place */ outlen = g_base64_decode_step (s, inlen, (guchar *)s, &state, &save); t = lua_newuserdata (L, sizeof (*t)); rspamd_lua_setclass (L, "rspamd{text}", -1); t->start = s; t->len = outlen; t->own = grab_own; } else { t = lua_newuserdata (L, sizeof (*t)); rspamd_lua_setclass (L, "rspamd{text}", -1); t->len = (inlen / 4) * 3 + 3; t->start = g_malloc (t->len); outlen = g_base64_decode_step (s, inlen, (guchar *)t->start, &state, &save); t->len = outlen; t->own = TRUE; } } else { lua_pushnil (L); } return 1; }
static gint lua_util_encode_base64 (lua_State *L) { struct rspamd_lua_text *t; const gchar *s = NULL; gchar *out; gsize inlen, outlen; guint str_lim = 0; if (lua_type (L, 1) == LUA_TSTRING) { s = luaL_checklstring (L, 1, &inlen); } else if (lua_type (L, 1) == LUA_TUSERDATA) { t = lua_check_text (L, 1); if (t != NULL) { s = t->start; inlen = t->len; } } if (lua_gettop (L) > 1) { str_lim = luaL_checknumber (L, 2); } if (s == NULL) { lua_pushnil (L); } else { out = rspamd_encode_base64 (s, inlen, str_lim, &outlen); if (out != NULL) { t = lua_newuserdata (L, sizeof (*t)); rspamd_lua_setclass (L, "rspamd{text}", -1); t->start = out; t->len = outlen; /* Need destruction */ t->own = TRUE; } else { lua_pushnil (L); } } return 1; }
/*** * @function rspamd_cryptobox.verify_memory(pk, sig, data) * Check memory using specified cryptobox key and signature * @param {pubkey} pk public key to verify * @param {sig} signature to check * @param {string} data data to check signature against * @return {boolean} `true` - if string matches cryptobox signature */ static gint lua_cryptobox_verify_memory (lua_State *L) { struct rspamd_cryptobox_pubkey *pk; rspamd_fstring_t *signature; struct rspamd_lua_text *t; const gchar *data; gsize len; gint ret; pk = lua_check_cryptobox_pubkey (L, 1); signature = lua_check_cryptobox_sign (L, 2); if (lua_isuserdata (L, 3)) { t = lua_check_text (L, 3); if (!t) { return luaL_error (L, "invalid arguments"); } data = t->start; len = t->len; } else { data = luaL_checklstring (L, 3, &len); } if (pk != NULL && signature != NULL && data != NULL) { ret = rspamd_cryptobox_verify (signature->str, data, len, rspamd_pubkey_get_pk (pk, NULL), RSPAMD_CRYPTOBOX_MODE_25519); if (ret) { lua_pushboolean (L, 1); } else { lua_pushboolean (L, 0); } } else { return luaL_error (L, "invalid arguments"); } return 1; }
/*** * @function rspamd_cryptobox.sign_memory(kp, data) * Sign data using specified keypair * @param {keypair} kp keypair to sign * @param {string} data * @return {cryptobox_signature} signature object */ static gint lua_cryptobox_sign_memory (lua_State *L) { struct rspamd_cryptobox_keypair *kp; const gchar *data; struct rspamd_lua_text *t; gsize len = 0; rspamd_fstring_t *sig, **psig; kp = lua_check_cryptobox_keypair (L, 1); if (lua_isuserdata (L, 2)) { t = lua_check_text (L, 2); if (!t) { return luaL_error (L, "invalid arguments"); } data = t->start; len = t->len; } else { data = luaL_checklstring (L, 2, &len); } if (!kp || !data) { return luaL_error (L, "invalid arguments"); } sig = rspamd_fstring_sized_new (rspamd_cryptobox_signature_bytes ( rspamd_keypair_alg (kp))); rspamd_cryptobox_sign (sig->str, &sig->len, data, len, rspamd_keypair_component (kp, RSPAMD_KEYPAIR_COMPONENT_SK, NULL), rspamd_keypair_alg (kp)); psig = lua_newuserdata (L, sizeof (void *)); *psig = sig; rspamd_lua_setclass (L, "rspamd{cryptobox_signature}", -1); return 1; }
/*** * @method cryptobox_hash:update(data) * Updates hash with the specified data (hash should not be finalized using `hex` or `bin` methods) * @param {string} data data to hash */ static gint lua_cryptobox_hash_update (lua_State *L) { rspamd_cryptobox_hash_state_t *h = lua_check_cryptobox_hash (L, 1); const gchar *data; struct rspamd_lua_text *t; gsize len; if (lua_isuserdata (L, 2)) { t = lua_check_text (L, 2); if (!t) { return luaL_error (L, "invalid arguments"); } data = t->start; len = t->len; } else { data = luaL_checklstring (L, 2, &len); } if (lua_isnumber (L, 3)) { gsize nlen = lua_tonumber (L, 3); if (nlen > len) { return luaL_error (L, "invalid length: %d while %d is available", (int)nlen, (int)len); } len = nlen; } if (h && data) { rspamd_cryptobox_hash_update (h, data, len); } else { return luaL_error (L, "invalid arguments"); } return 0; }
/*** * @function rspamd_cryptobox_signature.create(data) * Creates signature object from raw data * @param {data} raw signature data * @return {cryptobox_signature} signature object */ static gint lua_cryptobox_signature_create (lua_State *L) { rspamd_fstring_t *sig, **psig; struct rspamd_lua_text *t; const gchar *data; gsize dlen; if (lua_isuserdata (L, 1)) { t = lua_check_text (L, 1); if (!t) { return luaL_error (L, "invalid arguments"); } data = t->start; dlen = t->len; } else { data = luaL_checklstring (L, 1, &dlen); } if (data != NULL) { if (dlen == rspamd_cryptobox_signature_bytes (RSPAMD_CRYPTOBOX_MODE_25519)) { sig = rspamd_fstring_new_init (data, dlen); psig = lua_newuserdata (L, sizeof (rspamd_fstring_t *)); rspamd_lua_setclass (L, "rspamd{cryptobox_signature}", -1); *psig = sig; } } else { return luaL_error (L, "bad input arguments"); } return 1; }
static gint lua_util_tokenize_text (lua_State *L) { const gchar *in = NULL; gsize len, pos, ex_len, i; GList *exceptions = NULL, *cur; struct rspamd_lua_text *t; struct process_exception *ex; GArray *res; rspamd_fstring_t *w; gboolean compat = FALSE; if (lua_type (L, 1) == LUA_TSTRING) { in = luaL_checklstring (L, 1, &len); } else if (lua_type (L, 1) == LUA_TTABLE) { t = lua_check_text (L, 1); if (t) { in = t->start; len = t->len; } } if (in == NULL) { lua_pushnil (L); return 1; } if (lua_gettop (L) > 1 && lua_type (L, 2) == LUA_TTABLE) { lua_pushvalue (L, 2); lua_pushnil (L); while (lua_next (L, -2) != 0) { if (lua_type (L, -1) == LUA_TTABLE) { lua_rawgeti (L, -1, 1); pos = luaL_checknumber (L, -1); lua_pop (L, 1); lua_rawgeti (L, -1, 2); ex_len = luaL_checknumber (L, -1); lua_pop (L, 1); if (ex_len > 0) { ex = g_slice_alloc (sizeof (*ex)); ex->pos = pos; ex->len = ex_len; exceptions = g_list_prepend (exceptions, ex); } } lua_pop (L, 1); } lua_pop (L, 1); } if (lua_gettop (L) > 2 && lua_type (L, 3) == LUA_TBOOLEAN) { compat = lua_toboolean (L, 3); } if (exceptions) { exceptions = g_list_reverse (exceptions); } res = rspamd_tokenize_text ((gchar *)in, len, TRUE, 0, exceptions, compat); if (res == NULL) { lua_pushnil (L); } else { lua_newtable (L); for (i = 0; i < res->len; i ++) { w = &g_array_index (res, rspamd_fstring_t, i); lua_pushlstring (L, w->begin, w->len); lua_rawseti (L, -2, i + 1); } } cur = exceptions; while (cur) { ex = cur->data; g_slice_free1 (sizeof (*ex), ex); cur = g_list_next (cur); } g_list_free (exceptions); return 1; }