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 
38 static const char smtp_tx_mt[] = "suricata:smtp:tx";
39 
40 struct LuaSmtpTx {
41  SCLuaTxRef ref; /* (flow, tx id); the tx is resolved on demand */
42 };
43 
44 static int LuaSmtpGetTx(lua_State *L)
45 {
46  if (!(LuaStateNeedProto(L, ALPROTO_SMTP))) {
47  return LuaCallbackError(L, "error: protocol not SMTP");
48  }
49 
50  /* prefer the transaction the engine is inspecting (the match setup
51  * sets the registry entry in the tx-inspection phase); in the plain
52  * packet phase the entry is empty and the flow's current
53  * transaction is the one the script wants */
54  uint64_t tx_id;
56  if (tx != NULL) {
57  tx_id = LuaStateGetTxId(L);
58  } else {
59  Flow *flow = LuaStateGetFlow(L);
60  if (flow == NULL) {
61  return LuaCallbackError(L, "error: no flow found");
62  }
63  SMTPState *state = (SMTPState *)FlowGetAppState(flow);
64  if (state == NULL) {
65  return LuaCallbackError(L, "error: no SMTP state");
66  }
67  tx = state->curr_tx;
68  if (tx == NULL) {
69  return LuaCallbackError(L, "error: no SMTP transaction found");
70  }
71  tx_id = tx->tx_id;
72  }
73 
74  struct LuaSmtpTx *lua_tx = SCLuaNewUserData(L, SCLUA_TUD_SMTP_TX, sizeof(*lua_tx));
75  if (lua_tx == NULL) {
76  return LuaCallbackError(L, "error: fail to allocate user data");
77  }
78  SCLuaTxRefInit(L, &lua_tx->ref, tx_id);
79 
80  luaL_getmetatable(L, smtp_tx_mt);
81  lua_setmetatable(L, -2);
82 
83  return 1;
84 }
85 
86 static int LuaSmtpTxGetMimeField(lua_State *L)
87 {
88  struct LuaSmtpTx *ltx = SCLuaCheckUserData(L, 1, smtp_tx_mt, SCLUA_TUD_SMTP_TX);
89  if (ltx == NULL) {
90  lua_pushnil(L);
91  return 1;
92  }
93  SCLUA_RESOLVE_TX(L, &ltx->ref, txptr);
94  SMTPTransaction *tx = (SMTPTransaction *)txptr;
95 
96  if (tx->mime_state == NULL) {
97  return LuaCallbackError(L, "no mime state");
98  }
99 
100  const char *name = luaL_checkstring(L, 2);
101  if (name == NULL) {
102  return LuaCallbackError(L, "2nd argument missing, empty or wrong type");
103  }
104 
105  const uint8_t *field_value;
106  uint32_t field_len;
107  if (SCMimeSmtpGetHeader(tx->mime_state, name, &field_value, &field_len)) {
108  return LuaPushStringBuffer(L, field_value, field_len);
109  }
110 
111  return LuaCallbackError(L, "request mime field not found");
112 }
113 
114 static int LuaSmtpTxGetMimeList(lua_State *L)
115 {
116  struct LuaSmtpTx *ltx = SCLuaCheckUserData(L, 1, smtp_tx_mt, SCLUA_TUD_SMTP_TX);
117  if (ltx == NULL) {
118  lua_pushnil(L);
119  return 1;
120  }
121  SCLUA_RESOLVE_TX(L, &ltx->ref, txptr);
122  SMTPTransaction *tx = (SMTPTransaction *)txptr;
123 
124  if (tx->mime_state == NULL) {
125  return LuaCallbackError(L, "no mime state");
126  }
127 
128  const uint8_t *field_name;
129  uint32_t field_len;
130  /* the FFI accessor is 0-based; the Lua table is 1-based */
131  int num = 0;
132  lua_newtable(L);
133  while (SCMimeSmtpGetHeaderName(tx->mime_state, &field_name, &field_len, (uint32_t)num)) {
134  lua_pushinteger(L, num + 1);
135  LuaPushStringBuffer(L, field_name, field_len);
136  lua_settable(L, -3);
137  num++;
138  }
139  return 1;
140 }
141 
142 static int LuaSmtpTxGetMailFrom(lua_State *L)
143 {
144  struct LuaSmtpTx *ltx = SCLuaCheckUserData(L, 1, smtp_tx_mt, SCLUA_TUD_SMTP_TX);
145  if (ltx == NULL) {
146  lua_pushnil(L);
147  return 1;
148  }
149  SCLUA_RESOLVE_TX(L, &ltx->ref, txptr);
150  SMTPTransaction *tx = (SMTPTransaction *)txptr;
151 
152  if (tx->mail_from == NULL || tx->mail_from_len == 0) {
153  lua_pushnil(L);
154  return 1;
155  }
156 
157  return LuaPushStringBuffer(L, tx->mail_from, tx->mail_from_len);
158 }
159 
160 static int LuaSmtpTxGetRcptList(lua_State *L)
161 {
162  struct LuaSmtpTx *ltx = SCLuaCheckUserData(L, 1, smtp_tx_mt, SCLUA_TUD_SMTP_TX);
163  if (ltx == NULL) {
164  lua_pushnil(L);
165  return 1;
166  }
167  SCLUA_RESOLVE_TX(L, &ltx->ref, txptr);
168  SMTPTransaction *tx = (SMTPTransaction *)txptr;
169 
170  /* Create a new table in luastate for rcpt list */
171  lua_newtable(L);
172  /* rcpt var for iterator */
173  int u = 1;
174  SMTPString *rcpt;
175 
176  TAILQ_FOREACH (rcpt, &tx->rcpt_to_list, next) {
177  lua_pushinteger(L, u++);
178  LuaPushStringBuffer(L, rcpt->str, rcpt->len);
179  lua_settable(L, -3);
180  }
181 
182  return 1;
183 }
184 
185 static const struct luaL_Reg smtptxlib[] = {
186  { "get_mime_field", LuaSmtpTxGetMimeField },
187  { "get_mime_list", LuaSmtpTxGetMimeList },
188  { "get_mail_from", LuaSmtpTxGetMailFrom },
189  { "get_rcpt_list", LuaSmtpTxGetRcptList },
190  { NULL, NULL },
191 };
192 
193 static const struct luaL_Reg smtplib[] = {
194  { "get_tx", LuaSmtpGetTx },
195  { NULL, NULL },
196 };
197 
199 {
200  luaL_newmetatable(L, smtp_tx_mt);
201  lua_pushvalue(L, -1);
202  lua_setfield(L, -2, "__index");
203  luaL_setfuncs(L, smtptxlib, 0);
204 
205  luaL_newlib(L, smtplib);
206  return 1;
207 }
SMTPState_
Definition: app-layer-smtp.h:131
util-lua-common.h
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
name
const char * name
Definition: detect-engine-proto.c:47
util-lua.h
LuaCallbackError
int LuaCallbackError(lua_State *luastate, const char *msg)
Definition: util-lua-common.c:218
SCLuaTxRef_
Definition: util-lua-common.h:92
Flow_
Flow data structure.
Definition: flow.h:359
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
lua_State
struct lua_State lua_State
Definition: suricata-common.h:527
ALPROTO_SMTP
@ ALPROTO_SMTP
Definition: app-layer-protos.h:38
SMTPTransaction_::mail_from
uint8_t * mail_from
Definition: app-layer-smtp.h:103
SMTPState_::curr_tx
SMTPTransaction * curr_tx
Definition: app-layer-smtp.h:133
SCLuaCheckUserData
void * SCLuaCheckUserData(lua_State *L, int idx, const char *mt, uint32_t type_id)
Definition: util-lua-common.c:101
SMTPTransaction_
Definition: app-layer-smtp.h:85
SMTPTransaction_::mail_from_len
uint16_t mail_from_len
Definition: app-layer-smtp.h:104
LuaSmtpTx
Definition: util-lua-smtp.c:40
SCLuaNewUserData
void * SCLuaNewUserData(lua_State *L, uint32_t type_id, size_t size)
Definition: util-lua-common.c:42
util-lua-smtp.h
SMTPString_::len
uint16_t len
Definition: app-layer-smtp.h:68
LuaStateGetTX
void * LuaStateGetTX(lua_State *luastate)
get tx pointer from the lua state
Definition: util-lua.c:234
LuaStateGetTxId
uint64_t LuaStateGetTxId(lua_State *luastate)
get tx id from the lua state
Definition: util-lua.c:240
suricata-common.h
SMTPTransaction_::tx_id
uint64_t tx_id
Definition: app-layer-smtp.h:87
SMTPString_
Definition: app-layer-smtp.h:66
LuaSmtpTx::ref
SCLuaTxRef ref
Definition: util-lua-smtp.c:41
SCLuaLoadSmtpLib
int SCLuaLoadSmtpLib(lua_State *L)
Definition: util-lua-smtp.c:198
SCLUA_TUD_SMTP_TX
@ SCLUA_TUD_SMTP_TX
Definition: util-lua-common.h:64
SCLUA_RESOLVE_TX
#define SCLUA_RESOLVE_TX(L, refp, txvar)
Definition: util-lua-common.h:128
LuaStateGetFlow
Flow * LuaStateGetFlow(lua_State *luastate)
get flow pointer from lua state
Definition: util-lua.c:260
SCLuaTxRefInit
void SCLuaTxRefInit(lua_State *L, SCLuaTxRef *ref, uint64_t tx_id)
Definition: util-lua-common.c:164
SMTPString_::str
uint8_t * str
Definition: app-layer-smtp.h:67
app-layer-smtp.h
LuaStateNeedProto
int LuaStateNeedProto(lua_State *luastate, AppProto alproto)
Definition: util-lua-common.c:289
LuaPushStringBuffer
int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len)
Definition: util-lua.c:380
SMTPTransaction_::mime_state
MimeStateSMTP * mime_state
Definition: app-layer-smtp.h:100