suricata
util-lua-smtp.c
Go to the documentation of this file.
1/* Copyright (C) 2014-2025 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author casec Bachelors group
22 * \author Lauritz Prag Sømme <lauritz24@me.com>
23 * \author Levi Tobiassen <levi.tobiassen@gmail.com>
24 * \author Stian Hoel Bergseth <stian.bergseth@hig.no>
25 * \author Vinjar Hillestad <vinjar.hillestad@hig.no>
26 */
27
28#include "suricata-common.h"
29#include "app-layer-smtp.h"
30
31#include "util-lua.h"
32#include "util-lua-common.h"
33#include "util-lua-smtp.h"
34
35#include "lua.h"
36#include "lauxlib.h"
37
38static const char smtp_tx_mt[] = "suricata:smtp:tx";
39
43
44static int LuaSmtpGetTx(lua_State *L)
45{
47 return LuaCallbackError(L, "error: protocol not SMTP");
48 }
49
50 Flow *flow = LuaStateGetFlow(L);
51 if (flow == NULL) {
52 return LuaCallbackError(L, "error: no flow found");
53 }
54
55 SMTPState *state = (SMTPState *)FlowGetAppState(flow);
56 if (state == NULL) {
57 return LuaCallbackError(L, "error: no SMTP state");
58 }
59
60 SMTPTransaction *tx = state->curr_tx;
61 if (tx == NULL) {
62 return LuaCallbackError(L, "error: no SMTP transaction found");
63 }
64
65 struct LuaSmtpTx *lua_tx = (struct LuaSmtpTx *)lua_newuserdata(L, sizeof(*lua_tx));
66 if (lua_tx == NULL) {
67 return LuaCallbackError(L, "error: fail to allocate user data");
68 }
69 lua_tx->tx = tx;
70
71 luaL_getmetatable(L, smtp_tx_mt);
72 lua_setmetatable(L, -2);
73
74 return 1;
75}
76
77static int LuaSmtpTxGetMimeField(lua_State *L)
78{
79 struct LuaSmtpTx *tx = luaL_checkudata(L, 1, smtp_tx_mt);
80
81 if (tx->tx->mime_state == NULL) {
82 return LuaCallbackError(L, "no mime state");
83 }
84
85 const char *name = luaL_checkstring(L, 2);
86 if (name == NULL) {
87 return LuaCallbackError(L, "2nd argument missing, empty or wrong type");
88 }
89
90 const uint8_t *field_value;
91 uint32_t field_len;
92 if (SCMimeSmtpGetHeader(tx->tx->mime_state, name, &field_value, &field_len)) {
93 return LuaPushStringBuffer(L, field_value, field_len);
94 }
95
96 return LuaCallbackError(L, "request mime field not found");
97}
98
99static int LuaSmtpTxGetMimeList(lua_State *L)
100{
101 struct LuaSmtpTx *tx = luaL_checkudata(L, 1, smtp_tx_mt);
102
103 if (tx->tx->mime_state == NULL) {
104 return LuaCallbackError(L, "no mime state");
105 }
106
107 const uint8_t *field_name;
108 uint32_t field_len;
109 int num = 1;
110 lua_newtable(L);
111 while (SCMimeSmtpGetHeaderName(tx->tx->mime_state, &field_name, &field_len, (uint32_t)num)) {
112 if (field_len != 0) {
113 lua_pushinteger(L, num++);
114 LuaPushStringBuffer(L, field_name, field_len);
115 lua_settable(L, -3);
116 }
117 }
118 return 1;
119}
120
121static int LuaSmtpTxGetMailFrom(lua_State *L)
122{
123 struct LuaSmtpTx *tx = luaL_checkudata(L, 1, smtp_tx_mt);
124
125 if (tx->tx->mail_from == NULL || tx->tx->mail_from_len == 0) {
126 lua_pushnil(L);
127 return 1;
128 }
129
130 return LuaPushStringBuffer(L, tx->tx->mail_from, tx->tx->mail_from_len);
131}
132
133static int LuaSmtpTxGetRcptList(lua_State *L)
134{
135 struct LuaSmtpTx *tx = luaL_checkudata(L, 1, smtp_tx_mt);
136
137 /* Create a new table in luastate for rcpt list */
138 lua_newtable(L);
139 /* rcpt var for iterator */
140 int u = 1;
141 SMTPString *rcpt;
142
143 TAILQ_FOREACH (rcpt, &tx->tx->rcpt_to_list, next) {
144 lua_pushinteger(L, u++);
145 LuaPushStringBuffer(L, rcpt->str, rcpt->len);
146 lua_settable(L, -3);
147 }
148
149 return 1;
150}
151
152static const struct luaL_Reg smtptxlib[] = {
153 { "get_mime_field", LuaSmtpTxGetMimeField },
154 { "get_mime_list", LuaSmtpTxGetMimeList },
155 { "get_mail_from", LuaSmtpTxGetMailFrom },
156 { "get_rcpt_list", LuaSmtpTxGetRcptList },
157 { NULL, NULL },
158};
159
160static const struct luaL_Reg smtplib[] = {
161 { "get_tx", LuaSmtpGetTx },
162 { NULL, NULL },
163};
164
166{
167 luaL_newmetatable(L, smtp_tx_mt);
168 lua_pushvalue(L, -1);
169 lua_setfield(L, -2, "__index");
170 luaL_setfuncs(L, smtptxlib, 0);
171
172 luaL_newlib(L, smtplib);
173 return 1;
174}
struct HtpBodyChunk_ * next
@ ALPROTO_SMTP
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:252
Flow data structure.
Definition flow.h:356
SMTPTransaction * tx
SMTPTransaction * curr_tx
uint8_t * str
MimeStateSMTP * mime_state
struct lua_State lua_State
const char * name
int LuaStateNeedProto(lua_State *luastate, AppProto alproto)
int LuaCallbackError(lua_State *luastate, const char *msg)
int SCLuaLoadSmtpLib(lua_State *L)
int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len)
Definition util-lua.c:319
Flow * LuaStateGetFlow(lua_State *luastate)
get flow pointer from lua state
Definition util-lua.c:161