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