suricata
util-lua-smtp.c
Go to the documentation of this file.
1 /* Copyright (C) 2014 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 
30 #include "conf.h"
31 
32 #include "threads.h"
33 #include "threadvars.h"
34 #include "tm-threads.h"
35 #include "output.h"
36 
37 #include "app-layer-smtp.h"
38 
39 #ifdef HAVE_LUA
40 
41 #include <lua.h>
42 #include <lualib.h>
43 
44 #include "util-lua.h"
45 #include "util-lua-common.h"
46 #include "util-lua-smtp.h"
47 #include "util-file.h"
48 
49 /*
50  * \brief internal function used by SMTPGetMimeField
51  *
52  * \param luastate luastate stack to use and push attributes to
53  * \param flow network flow of SMTP packets
54  * \param name name of the attribute to extract from MimeDecField
55  *
56  * \retval 1 if success mimefield found and pushed to stack. Returns error
57  * int and msg pushed to luastate stack if error occurs.
58  */
59 
60 static int GetMimeDecField(lua_State *luastate, Flow *flow, const char *name)
61 {
62  /* extract state from flow */
63  SMTPState *state = (SMTPState *) FlowGetAppState(flow);
64  /* check that state exists */
65  if(state == NULL) {
66  return LuaCallbackError(luastate, "Internal error: no state in flow");
67  }
68  /* pointer to current transaction in state */
69  SMTPTransaction *smtp_tx = state->curr_tx;
70  if(smtp_tx == NULL) {
71  return LuaCallbackError(luastate, "Transaction ending or not found");
72  }
73  /* pointer to tail of msg list of MimeDecEntities in current transaction. */
74  MimeDecEntity *mime = smtp_tx->msg_tail;
75  /* check if msg_tail was hit */
76  if(mime == NULL){
77  return LuaCallbackError(luastate, "Internal error: no fields in transaction");
78  }
79  /* extract MIME field based on specific field name. */
80  MimeDecField *field = MimeDecFindField(mime, name);
81  /* check MIME field */
82  if(field == NULL) {
83  return LuaCallbackError(luastate, "Error: mimefield not found");
84  }
85  /* return extracted field. */
86  if(field->value == NULL || field->value_len == 0){
87  return LuaCallbackError(luastate, "Error, pointer error");
88  }
89 
90  return LuaPushStringBuffer(luastate, field->value, field->value_len);
91 }
92 
93 /**
94  * \brief Function extracts specific MIME field based on argument from luastate
95  * stack then pushing the attribute onto the luastate stack.
96  *
97  * \param luastate luastate stack to pop and push attributes for I/O to lua
98  *
99  * \retval 1 if success mimefield found and pushed to stack. Returns error
100  * int and msg pushed to luastate stack if error occurs.
101  */
102 
103 static int SMTPGetMimeField(lua_State *luastate)
104 {
105  if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) {
106  return LuaCallbackError(luastate, "error: protocol not SMTP");
107  }
108  Flow *flow = LuaStateGetFlow(luastate);
109  /* check that flow exist */
110  if(flow == NULL) {
111  return LuaCallbackError(luastate, "Error: no flow found");
112  }
113  const char *name = LuaGetStringArgument(luastate, 1);
114  if (name == NULL)
115  return LuaCallbackError(luastate, "1st argument missing, empty or wrong type");
116 
117  GetMimeDecField(luastate, flow, name);
118 
119  return 1;
120 }
121 
122 /**
123  * \brief Internal function used by SMTPGetMimeList
124  *
125  * \param luastate luastate stack to pop and push attributes for I/O to lua
126  * \param flow network flow of SMTP packets
127  *
128  * \retval 1 if the mimelist table is pushed to luastate stack.
129  * Returns error int and msg pushed to luastate stack if error occurs.
130 */
131 
132 static int GetMimeList(lua_State *luastate, Flow *flow)
133 {
134 
135  SMTPState *state = (SMTPState *) FlowGetAppState(flow);
136  if(state == NULL) {
137  return LuaCallbackError(luastate, "Error: no SMTP state");
138  }
139  /* Create a pointer to the current SMTPtransaction */
140  SMTPTransaction *smtp_tx = state->curr_tx;
141  if(smtp_tx == NULL) {
142  return LuaCallbackError(luastate, "Error: no SMTP transaction found");
143  }
144  /* Create a pointer to the tail of MimeDecEntity list */
145  MimeDecEntity *mime = smtp_tx->msg_tail;
146  if(mime == NULL) {
147  return LuaCallbackError(luastate, "Error: no mime entity found");
148  }
149  MimeDecField *field = mime->field_list;
150  if(field == NULL) {
151  return LuaCallbackError(luastate, "Error: no field_list found");
152  }
153  if(field->name == NULL || field->name_len == 0) {
154  return LuaCallbackError(luastate, "Error: field has no name");
155  }
156  /* Counter of MIME fields found */
157  int num = 1;
158  /* loop trough the list of mimeFields, printing each name found */
159  lua_newtable(luastate);
160  while (field != NULL) {
161  if(field->name != NULL && field->name_len != 0) {
162  lua_pushinteger(luastate,num++);
163  LuaPushStringBuffer(luastate, field->name, field->name_len);
164  lua_settable(luastate,-3);
165  }
166  field = field->next;
167  }
168  return 1;
169 }
170 
171 /**
172  * \brief Lists name and value to all MIME fields which
173  * is included in a SMTP transaction.
174  *
175  * \param luastate luastate stack to pop and push attributes for I/O to lua.
176  *
177  * \retval 1 if the table is pushed to lua.
178  * Returns error int and msg pushed to luastate stack if error occurs
179  *
180  */
181 
182 static int SMTPGetMimeList(lua_State *luastate)
183 {
184  /* Check if right protocol */
185  if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) {
186  return LuaCallbackError(luastate, "Error: protocol not SMTP");
187  }
188  /* Extract network flow */
189  Flow *flow = LuaStateGetFlow(luastate);
190  if(flow == NULL) {
191  return LuaCallbackError(luastate, "Error: no flow found");
192  }
193 
194  GetMimeList(luastate, flow);
195 
196  return 1;
197 }
198 
199 /**
200  * \brief internal function used by SMTPGetMailFrom
201  *
202  * \param luastate luastate stack to pop and push attributes for I/O to lua.
203  * \param flow flow to get state for SMTP
204  *
205  * \retval 1 if mailfrom field found.
206  * Returns error int and msg pushed to luastate stack if error occurs
207  */
208 
209 static int GetMailFrom(lua_State *luastate, Flow *flow)
210 {
211  /* Extract SMTPstate from current flow */
212  SMTPState *state = (SMTPState *) FlowGetAppState(flow);
213 
214  if(state == NULL) {
215  return LuaCallbackError(luastate, "Internal Error: no state");
216  }
217  SMTPTransaction *smtp_tx = state->curr_tx;
218  if(smtp_tx == NULL) {
219  return LuaCallbackError(luastate, "Internal Error: no SMTP transaction");
220  }
221  if(smtp_tx->mail_from == NULL || smtp_tx->mail_from_len == 0) {
222  return LuaCallbackError(luastate, "MailFrom not found");
223  }
224  return LuaPushStringBuffer(luastate, smtp_tx->mail_from, smtp_tx->mail_from_len);
225  /* Returns 1 because we never push more then 1 item to the lua stack */
226 }
227 
228 /**
229  * \brief Extracts mail_from parameter from SMTPState.
230  * Attribute may also be available from mimefields, although there is no
231  * guarantee of it existing as mime.
232  *
233  * \param luastate luastate stack to pop and push attributes for I/O to lua.
234  *
235  * \retval 1 if mailfrom field found.
236  * Returns error int and msg pushed to luastate stack if error occurs
237  */
238 
239 static int SMTPGetMailFrom(lua_State *luastate)
240 {
241  /* check protocol */
242  if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) {
243  return LuaCallbackError(luastate, "Error: protocol not SMTP");
244  }
245  /* Extract flow, with lockhint to check mutexlocking */
246  Flow *flow = LuaStateGetFlow(luastate);
247  if(flow == NULL) {
248  return LuaCallbackError(luastate, "Internal Error: no flow");
249  }
250 
251  GetMailFrom(luastate, flow);
252 
253  return 1;
254 }
255 
256 /**
257  * \brief intern function used by SMTPGetRcpList
258  *
259  * \param luastate luastate stack for internal communication with Lua.
260  * Used to hand over data to the receiving luascript.
261  *
262  * \retval 1 if the table is pushed to lua.
263  * Returns error int and msg pushed to luastate stack if error occurs
264  */
265 
266 static int GetRcptList(lua_State *luastate, Flow *flow)
267 {
268 
269  SMTPState *state = (SMTPState *) FlowGetAppState(flow);
270  if(state == NULL) {
271  return LuaCallbackError(luastate, "Internal error, no state");
272  }
273 
274  SMTPTransaction *smtp_tx = state->curr_tx;
275  if(smtp_tx == NULL) {
276  return LuaCallbackError(luastate, "No more tx, or tx not found");
277  }
278 
279  /* Create a new table in luastate for rcpt list */
280  lua_newtable(luastate);
281  /* rcpt var for iterator */
282  int u = 1;
283  SMTPString *rcpt;
284 
285  TAILQ_FOREACH(rcpt, &smtp_tx->rcpt_to_list, next) {
286  lua_pushinteger(luastate, u++);
287  LuaPushStringBuffer(luastate, rcpt->str, rcpt->len);
288  lua_settable(luastate, -3);
289  }
290  /* return 1 since we always push one table to luastate */
291  return 1;
292 }
293 
294 /**
295  * \brief function loops through rcpt-list located in
296  * flow->SMTPState->SMTPTransaction, adding all items to a table.
297  * Then pushing it to the luastate stack.
298  *
299  * \param luastate luastate stack for internal communication with Lua.
300  * Used to hand over data to the receiving luascript.
301  *
302  * \retval 1 if the table is pushed to lua.
303  * Returns error int and msg pushed to luastate stack if error occurs
304  */
305 
306 static int SMTPGetRcptList(lua_State *luastate)
307 {
308  /* check protocol */
309  if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) {
310  return LuaCallbackError(luastate, "Error: protocol not SMTP");
311  }
312  /* Extract flow, with lockhint to check mutexlocking */
313  Flow *flow = LuaStateGetFlow(luastate);
314  if(flow == NULL) {
315  return LuaCallbackError(luastate, "Internal error: no flow");
316  }
317 
318  GetRcptList(luastate, flow);
319 
320  /* return 1 since we always push one table to luastate */
321  return 1;
322 }
323 
324 int LuaRegisterSmtpFunctions(lua_State *luastate)
325 {
326 
327  lua_pushcfunction(luastate, SMTPGetMimeField);
328  lua_setglobal(luastate, "SMTPGetMimeField");
329 
330  lua_pushcfunction(luastate, SMTPGetMimeList);
331  lua_setglobal(luastate, "SMTPGetMimeList");
332 
333  lua_pushcfunction(luastate, SMTPGetMailFrom);
334  lua_setglobal(luastate, "SMTPGetMailFrom");
335 
336  lua_pushcfunction(luastate, SMTPGetRcptList);
337  lua_setglobal(luastate, "SMTPGetRcptList");
338 
339  return 0;
340 }
341 
342 #endif /* HAVE_LUA */
tm-threads.h
SMTPState_
Definition: app-layer-smtp.h:116
util-lua-common.h
SMTPTransaction_::msg_tail
MimeDecEntity * msg_tail
Definition: app-layer-smtp.h:87
MimeDecField::value
uint8_t * value
Definition: util-decode-mime.h:110
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
util-lua.h
threads.h
Flow_
Flow data structure.
Definition: flow.h:350
MimeDecEntity::field_list
MimeDecField * field_list
Definition: util-decode-mime.h:133
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
MimeDecField
This represents a header field name and associated value.
Definition: util-decode-mime.h:106
MimeDecField::name
uint8_t * name
Definition: util-decode-mime.h:107
ALPROTO_SMTP
@ ALPROTO_SMTP
Definition: app-layer-protos.h:32
SMTPTransaction_::mail_from
uint8_t * mail_from
Definition: app-layer-smtp.h:92
SMTPState_::curr_tx
SMTPTransaction * curr_tx
Definition: app-layer-smtp.h:118
MimeDecField::next
struct MimeDecField * next
Definition: util-decode-mime.h:111
SMTPTransaction_
Definition: app-layer-smtp.h:72
conf.h
SMTPTransaction_::mail_from_len
uint16_t mail_from_len
Definition: app-layer-smtp.h:93
util-lua-smtp.h
SMTPString_::len
uint16_t len
Definition: app-layer-smtp.h:67
util-file.h
MimeDecField::value_len
uint32_t value_len
Definition: util-decode-mime.h:109
suricata-common.h
lua_State
void lua_State
Definition: suricata-common.h:500
SMTPString_
Definition: app-layer-smtp.h:65
threadvars.h
MimeDecFindField
MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name)
Searches for a header field with the specified name.
Definition: util-decode-mime.c:325
MimeDecField::name_len
uint32_t name_len
Definition: util-decode-mime.h:108
SMTPString_::str
uint8_t * str
Definition: app-layer-smtp.h:66
app-layer-smtp.h
MimeDecEntity
This represents the MIME Entity (or also top level message) in a child-sibling tree.
Definition: util-decode-mime.h:132
output.h