]> git.ipfire.org Git - people/ms/suricata.git/blame - src/app-layer-smtp.c
file-hashing: added support for SHA-1 file hashing
[people/ms/suricata.git] / src / app-layer-smtp.c
CommitLineData
7fa22e84 1/* Copyright (C) 2007-2012 Open Information Security Foundation
576ec7da
AS
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 *
420befb1 21 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
576ec7da
AS
22 */
23
24#include "suricata.h"
25#include "suricata-common.h"
26#include "debug.h"
27#include "decode.h"
28#include "threads.h"
29
30#include "stream-tcp-private.h"
31#include "stream-tcp-reassemble.h"
32#include "stream-tcp.h"
33#include "stream.h"
34
429c6388
AS
35#include "app-layer.h"
36#include "app-layer-detect-proto.h"
576ec7da
AS
37#include "app-layer-protos.h"
38#include "app-layer-parser.h"
39#include "app-layer-smtp.h"
40
a49cbf8a 41#include "util-mpm.h"
576ec7da
AS
42#include "util-debug.h"
43#include "util-byte.h"
44#include "util-unittest.h"
576ec7da
AS
45#include "util-unittest-helper.h"
46#include "util-memcmp.h"
47#include "flow-util.h"
48
49#include "detect-engine.h"
50#include "detect-engine-state.h"
51#include "detect-parse.h"
52
5311cd48 53#include "decode-events.h"
5e2d9dbd 54#include "conf.h"
576ec7da 55
56b74c8b 56#include "util-mem.h"
26ba647d
GL
57#include "util-misc.h"
58
59/* content-limit default value */
4526aed2 60#define FILEDATA_CONTENT_LIMIT 100000
26ba647d 61/* content-inspect-min-size default value */
4526aed2 62#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768
26ba647d 63/* content-inspect-window default value */
4526aed2 64#define FILEDATA_CONTENT_INSPECT_WINDOW 4096
56b74c8b 65
576ec7da
AS
66#define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510
67
68#define SMTP_COMMAND_BUFFER_STEPS 5
69
70/* we are in process of parsing a fresh command. Just a placeholder. If we
71 * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */
72#define SMTP_PARSER_STATE_COMMAND_MODE 0x00
73/* we are in mode of parsing a command's data. Used when we are parsing tls
74 * or accepting the rfc 2822 mail after DATA command */
75#define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01
76/* Used when we are still in the process of parsing a server command. Used
77 * with multi-line replies and the stream is fragmented before all the lines
78 * for a response is seen */
79#define SMTP_PARSER_STATE_PARSING_SERVER_RESPONSE 0x02
80/* Used to indicate that the parser has seen the first reply */
81#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04
82/* Used to indicate that the parser is parsing a multiline reply */
83#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08
84
85/* Various SMTP commands
86 * We currently have var-ified just STARTTLS and DATA, since we need to them
87 * for state transitions. The rest are just indicate as OTHER_CMD. Other
88 * commands would be introduced as and when needed */
89#define SMTP_COMMAND_STARTTLS 1
90#define SMTP_COMMAND_DATA 2
d3ca65de 91#define SMTP_COMMAND_BDAT 3
576ec7da
AS
92/* not an actual command per se, but the mode where we accept the mail after
93 * DATA has it's own reply code for completion, from the server. We give this
94 * stage a pseudo command of it's own, so that we can add this to the command
95 * buffer to match with the reply */
d3ca65de 96#define SMTP_COMMAND_DATA_MODE 4
576ec7da 97/* All other commands are represented by this var */
d3ca65de 98#define SMTP_COMMAND_OTHER_CMD 5
576ec7da
AS
99
100/* Different EHLO extensions. Not used now. */
101#define SMTP_EHLO_EXTENSION_PIPELINING
102#define SMTP_EHLO_EXTENSION_SIZE
103#define SMTP_EHLO_EXTENSION_DSN
104#define SMTP_EHLO_EXTENSION_STARTTLS
105#define SMTP_EHLO_EXTENSION_8BITMIME
106
5311cd48
AS
107SCEnumCharMap smtp_decoder_event_table[ ] = {
108 { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY },
109 { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST",
110 SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST },
111 { "MAX_COMMAND_LINE_LEN_EXCEEDED",
112 SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED },
113 { "MAX_REPLY_LINE_LEN_EXCEEDED",
114 SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED },
115 { "INVALID_PIPELINED_SEQUENCE",
116 SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE },
117 { "BDAT_CHUNK_LEN_EXCEEDED",
118 SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED },
119 { "NO_SERVER_WELCOME_MESSAGE",
120 SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE },
121 { "TLS_REJECTED",
122 SMTP_DECODER_EVENT_TLS_REJECTED },
123 { "DATA_COMMAND_REJECTED",
124 SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED },
c2dc6867
DA
125
126 /* MIME Events */
127 { "MIME_PARSE_FAILED",
128 SMTP_DECODER_EVENT_MIME_PARSE_FAILED },
129 { "MIME_MALFORMED_MSG",
130 SMTP_DECODER_EVENT_MIME_MALFORMED_MSG },
131 { "MIME_INVALID_BASE64",
132 SMTP_DECODER_EVENT_MIME_INVALID_BASE64 },
133 { "MIME_INVALID_QP",
134 SMTP_DECODER_EVENT_MIME_INVALID_QP },
135 { "MIME_LONG_LINE",
136 SMTP_DECODER_EVENT_MIME_LONG_LINE },
137 { "MIME_LONG_ENC_LINE",
138 SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE },
139 { "MIME_LONG_HEADER_NAME",
140 SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME },
141 { "MIME_LONG_HEADER_VALUE",
142 SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE },
6d170cad
VJ
143 { "MIME_LONG_BOUNDARY",
144 SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG },
c2dc6867 145
10e2e2a8
EL
146 /* Invalid behavior or content */
147 { "DUPLICATE_FIELDS",
148 SMTP_DECODER_EVENT_DUPLICATE_FIELDS },
5dbedbfa
EL
149 { "UNPARSABLE_CONTENT",
150 SMTP_DECODER_EVENT_UNPARSABLE_CONTENT },
10e2e2a8 151
5311cd48
AS
152 { NULL, -1 },
153};
4d38a571 154
eec66c7b
VJ
155typedef struct SMTPThreadCtx_ {
156 MpmThreadCtx *smtp_mpm_thread_ctx;
157 PatternMatcherQueue *pmq;
158} SMTPThreadCtx;
159
e05034f5 160#define SMTP_MPM DEFAULT_MPM
4d38a571
AS
161
162static MpmCtx *smtp_mpm_ctx = NULL;
4d38a571
AS
163
164/* smtp reply codes. If an entry is made here, please make a simultaneous
165 * entry in smtp_reply_map */
166enum {
167 SMTP_REPLY_211,
168 SMTP_REPLY_214,
169 SMTP_REPLY_220,
170 SMTP_REPLY_221,
7850d896 171 SMTP_REPLY_235,
4d38a571
AS
172 SMTP_REPLY_250,
173 SMTP_REPLY_251,
174 SMTP_REPLY_252,
175
7850d896 176 SMTP_REPLY_334,
4d38a571
AS
177 SMTP_REPLY_354,
178
179 SMTP_REPLY_421,
180 SMTP_REPLY_450,
181 SMTP_REPLY_451,
182 SMTP_REPLY_452,
183 SMTP_REPLY_455,
184
185 SMTP_REPLY_500,
186 SMTP_REPLY_501,
187 SMTP_REPLY_502,
188 SMTP_REPLY_503,
189 SMTP_REPLY_504,
190 SMTP_REPLY_550,
191 SMTP_REPLY_551,
192 SMTP_REPLY_552,
193 SMTP_REPLY_553,
194 SMTP_REPLY_554,
195 SMTP_REPLY_555,
196};
197
198SCEnumCharMap smtp_reply_map[ ] = {
199 { "211", SMTP_REPLY_211 },
200 { "214", SMTP_REPLY_214 },
201 { "220", SMTP_REPLY_220 },
202 { "221", SMTP_REPLY_221 },
7850d896 203 { "235", SMTP_REPLY_235 },
4d38a571
AS
204 { "250", SMTP_REPLY_250 },
205 { "251", SMTP_REPLY_251 },
206 { "252", SMTP_REPLY_252 },
207
7850d896 208 { "334", SMTP_REPLY_334 },
4d38a571
AS
209 { "354", SMTP_REPLY_354 },
210
211 { "421", SMTP_REPLY_421 },
212 { "450", SMTP_REPLY_450 },
213 { "451", SMTP_REPLY_451 },
214 { "452", SMTP_REPLY_452 },
215 { "455", SMTP_REPLY_455 },
216
217 { "500", SMTP_REPLY_500 },
218 { "501", SMTP_REPLY_501 },
219 { "502", SMTP_REPLY_502 },
220 { "503", SMTP_REPLY_503 },
221 { "504", SMTP_REPLY_504 },
222 { "550", SMTP_REPLY_550 },
223 { "551", SMTP_REPLY_551 },
224 { "552", SMTP_REPLY_552 },
225 { "553", SMTP_REPLY_553 },
226 { "554", SMTP_REPLY_554 },
227 { "555", SMTP_REPLY_555 },
228 { NULL, -1 },
229};
c2dc6867 230
c2dc6867 231/* Create SMTP config structure */
e43ce0a9 232SMTPConfig smtp_config = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 0, STREAMING_BUFFER_CONFIG_INITIALIZER};
c2dc6867 233
752fdba9
EL
234static SMTPString *SMTPStringAlloc(void);
235
c2dc6867 236/**
e5c36952 237 * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML
c2dc6867
DA
238 * config file
239 *
240 * \return none
241 */
242static void SMTPConfigure(void) {
243
244 SCEnter();
245 int ret = 0, val;
246 intmax_t imval;
26ba647d
GL
247 uint32_t content_limit = 0;
248 uint32_t content_inspect_min_size = 0;
249 uint32_t content_inspect_window = 0;
c2dc6867 250
e5c36952 251 ConfNode *config = ConfGetNode("app-layer.protocols.smtp.mime");
c2dc6867
DA
252 if (config != NULL) {
253
254 ret = ConfGetChildValueBool(config, "decode-mime", &val);
255 if (ret) {
256 smtp_config.decode_mime = val;
257 }
258
259 ret = ConfGetChildValueBool(config, "decode-base64", &val);
260 if (ret) {
261 smtp_config.mime_config.decode_base64 = val;
262 }
263
264 ret = ConfGetChildValueBool(config, "decode-quoted-printable", &val);
265 if (ret) {
266 smtp_config.mime_config.decode_quoted_printable = val;
267 }
268
269 ret = ConfGetChildValueInt(config, "header-value-depth", &imval);
270 if (ret) {
271 smtp_config.mime_config.header_value_depth = (uint32_t) imval;
272 }
273
274 ret = ConfGetChildValueBool(config, "extract-urls", &val);
275 if (ret) {
276 smtp_config.mime_config.extract_urls = val;
277 }
99005584
EL
278
279 ret = ConfGetChildValueBool(config, "body-md5", &val);
280 if (ret) {
281 smtp_config.mime_config.body_md5 = val;
282 }
c2dc6867
DA
283 }
284
285 /* Pass mime config data to MimeDec API */
286 MimeDecSetConfig(&smtp_config.mime_config);
287
4526aed2
VJ
288 smtp_config.content_limit = FILEDATA_CONTENT_LIMIT;
289 smtp_config.content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW;
290 smtp_config.content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE;
291
26ba647d
GL
292 ConfNode *t = ConfGetNode("app-layer.protocols.smtp.inspected-tracker");
293 ConfNode *p = NULL;
294
4526aed2
VJ
295 if (t != NULL) {
296 TAILQ_FOREACH(p, &t->head, next) {
297 if (strcasecmp("content-limit", p->name) == 0) {
298 if (ParseSizeStringU32(p->val, &content_limit) < 0) {
299 SCLogWarning(SC_ERR_SIZE_PARSE,
300 "parsing content-limit %s failed", p->val);
301 content_limit = FILEDATA_CONTENT_LIMIT;
302 }
303 smtp_config.content_limit = content_limit;
26ba647d 304 }
26ba647d 305
4526aed2
VJ
306 if (strcasecmp("content-inspect-min-size", p->name) == 0) {
307 if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) {
308 SCLogWarning(SC_ERR_SIZE_PARSE,
309 "parsing content-inspect-min-size %s failed", p->val);
310 content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE;
311 }
312 smtp_config.content_inspect_min_size = content_inspect_min_size;
26ba647d 313 }
26ba647d 314
4526aed2
VJ
315 if (strcasecmp("content-inspect-window", p->name) == 0) {
316 if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) {
317 SCLogWarning(SC_ERR_SIZE_PARSE,
318 "parsing content-inspect-window %s failed", p->val);
319 content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW;
320 }
321 smtp_config.content_inspect_window = content_inspect_window;
26ba647d
GL
322 }
323 }
324 }
325
e43ce0a9
VJ
326 smtp_config.sbcfg.buf_size = content_limit ? content_limit : 256;
327
c2dc6867
DA
328 SCReturn;
329}
330
d209699a
VJ
331void SMTPSetEvent(SMTPState *s, uint8_t e)
332{
333 SCLogDebug("setting event %u", e);
334
335 if (s->curr_tx != NULL) {
336 AppLayerDecoderEventsSetEventRaw(&s->curr_tx->decoder_events, e);
337// s->events++;
338 return;
339 }
340 SCLogDebug("couldn't set event %u", e);
341}
342
56b74c8b
VJ
343static SMTPTransaction *SMTPTransactionCreate(void)
344{
345 SMTPTransaction *tx = SCCalloc(1, sizeof(*tx));
346 if (tx == NULL) {
347 return NULL;
348 }
349
752fdba9 350 TAILQ_INIT(&tx->rcpt_to_list);
56b74c8b
VJ
351 tx->mime_state = NULL;
352 return tx;
353}
354
9afaf14b
VJ
355/** \internal
356 * \brief update inspected tracker if it gets to far behind
357 *
358 * As smtp uses the FILE_USE_DETECT flag in the file API, we are responsible
359 * for making sure that File::content_inspected is not getting too far
360 * behind.
361 */
362static void SMTPPruneFiles(FileContainer *files)
363{
364 SCLogDebug("cfg: win %"PRIu32" min_size %"PRIu32,
365 smtp_config.content_inspect_window, smtp_config.content_inspect_min_size);
366
367 File *file = files->head;
368 while (file) {
e43ce0a9
VJ
369 SCLogDebug("file %p", file);
370 uint32_t window = smtp_config.content_inspect_window;
371 if (file->sb->stream_offset == 0)
372 window = MAX(window, smtp_config.content_inspect_min_size);
373
374 uint64_t file_size = FileSize(file);
375 uint64_t data_size = file_size - file->sb->stream_offset;
376
377 SCLogDebug("window %"PRIu32", file_size %"PRIu64", data_size %"PRIu64,
378 window, file_size, data_size);
379
380 if (data_size > (window * 3)) {
213f041c 381 uint64_t left_edge = file_size - window;
e43ce0a9
VJ
382 SCLogDebug("file->content_inspected now %"PRIu64, left_edge);
383 file->content_inspected = left_edge;
9afaf14b 384 }
c2dc6867 385
9afaf14b
VJ
386 file = file->next;
387 }
388}
389
aa4ad9d2
VJ
390static void FlagDetectStateNewFile(SMTPTransaction *tx)
391{
392 if (tx && tx->de_state) {
393 SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW set");
394 tx->de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW;
c4a9580f
VJ
395 } else if (tx == NULL) {
396 SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW NOT set, no TX");
397 } else if (tx->de_state == NULL) {
398 SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW NOT set, no TX DESTATE");
aa4ad9d2
VJ
399 }
400}
401
9afaf14b
VJ
402int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len,
403 MimeDecParseState *state)
404{
405 SCEnter();
c2dc6867
DA
406 int ret = MIME_DEC_OK;
407 Flow *flow = (Flow *) state->data;
408 SMTPState *smtp_state = (SMTPState *) flow->alstate;
409 MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data;
410 FileContainer *files = NULL;
411 uint16_t flags = 0;
412
413 /* Set flags */
414 if (flow->flags & FLOW_FILE_NO_STORE_TS) {
415 flags |= FILE_NOSTORE;
416 }
417
418 if (flow->flags & FLOW_FILE_NO_MAGIC_TS) {
419 flags |= FILE_NOMAGIC;
420 }
421
422 if (flow->flags & FLOW_FILE_NO_MD5_TS) {
423 flags |= FILE_NOMD5;
424 }
425
a6d928e2
DS
426 if (flow->flags & FLOW_FILE_NO_SHA1_TS) {
427 flags |= FILE_NOSHA1;
428 }
429
c2dc6867
DA
430 /* Find file */
431 if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) {
432
433 /* Make sure file container allocated */
434 if (smtp_state->files_ts == NULL) {
435 smtp_state->files_ts = FileContainerAlloc();
436 if (smtp_state->files_ts == NULL) {
437 ret = MIME_DEC_ERR_MEM;
438 SCLogError(SC_ERR_MEM_ALLOC, "Could not create file container");
e43eb76a 439 SCReturnInt(ret);
c2dc6867
DA
440 }
441 }
442 files = smtp_state->files_ts;
443
444 /* Open file if necessary */
445 if (state->body_begin) {
446
447 if (SCLogDebugEnabled()) {
448 SCLogDebug("Opening file...%u bytes", len);
449 printf("File - ");
450 for (uint32_t i = 0; i < entity->filename_len; i++) {
451 printf("%c", entity->filename[i]);
452 }
453 printf("\n");
454 }
455
456 /* Set storage flag if applicable since only the first file in the
457 * flow seems to be processed by the 'filestore' detector */
458 if (files->head != NULL && (files->head->flags & FILE_STORE)) {
459 flags |= FILE_STORE;
460 }
461
e43ce0a9 462 if (FileOpenFile(files, &smtp_config.sbcfg, (uint8_t *) entity->filename, entity->filename_len,
9afaf14b 463 (uint8_t *) chunk, len, flags|FILE_USE_DETECT) == NULL) {
c2dc6867
DA
464 ret = MIME_DEC_ERR_DATA;
465 SCLogDebug("FileOpenFile() failed");
466 }
aa4ad9d2 467 FlagDetectStateNewFile(smtp_state->curr_tx);
c2dc6867
DA
468
469 /* If close in the same chunk, then pass in empty bytes */
470 if (state->body_end) {
471
472 SCLogDebug("Closing file...%u bytes", len);
473
474 if (files->tail->state == FILE_STATE_OPENED) {
475 ret = FileCloseFile(files, (uint8_t *) NULL, 0, flags);
476 if (ret != 0) {
477 SCLogDebug("FileCloseFile() failed: %d", ret);
9d33131d 478 ret = MIME_DEC_ERR_DATA;
c2dc6867
DA
479 }
480 } else {
481 SCLogDebug("File already closed");
482 }
483 }
484 } else if (state->body_end) {
485 /* Close file */
486 SCLogDebug("Closing file...%u bytes", len);
487
56b74c8b 488 if (files && files->tail && files->tail->state == FILE_STATE_OPENED) {
c2dc6867
DA
489 ret = FileCloseFile(files, (uint8_t *) chunk, len, flags);
490 if (ret != 0) {
491 SCLogDebug("FileCloseFile() failed: %d", ret);
9d33131d 492 ret = MIME_DEC_ERR_DATA;
c2dc6867
DA
493 }
494 } else {
495 SCLogDebug("File already closed");
496 }
497 } else {
498 /* Append data chunk to file */
499 SCLogDebug("Appending file...%u bytes", len);
500
501 /* 0 is ok, -2 is not stored, -1 is error */
502 ret = FileAppendData(files, (uint8_t *) chunk, len);
503 if (ret == -2) {
504 ret = 0;
505 SCLogDebug("FileAppendData() - file no longer being extracted");
506 } else if (ret < 0) {
507 SCLogDebug("FileAppendData() failed: %d", ret);
9d33131d 508 ret = MIME_DEC_ERR_DATA;
c2dc6867
DA
509 }
510 }
511
9d33131d 512 if (ret == 0) {
c2dc6867
DA
513 SCLogDebug("Successfully processed file data!");
514 }
515 } else {
516 SCLogDebug("Body not a Ctnt_attachment");
517 }
518
519 if (files != NULL) {
9afaf14b 520 SMTPPruneFiles(files);
c2dc6867
DA
521 FilePrune(files);
522 }
e43eb76a 523
c2dc6867
DA
524 SCReturnInt(ret);
525}
576ec7da
AS
526
527/**
528 * \internal
529 * \brief Get the next line from input. It doesn't do any length validation.
530 *
531 * \param state The smtp state.
532 *
533 * \retval 0 On suceess.
534 * \retval -1 Either when we don't have any new lines to supply anymore or
535 * on failure.
536 */
537static int SMTPGetLine(SMTPState *state)
538{
7b0f261f 539 SCEnter();
1f07d152 540 void *ptmp;
7b0f261f 541
88115902
AS
542 /* we have run out of input */
543 if (state->input_len <= 0)
576ec7da
AS
544 return -1;
545
88115902
AS
546 /* toserver */
547 if (state->direction == 0) {
548 if (state->ts_current_line_lf_seen == 1) {
549 /* we have seen the lf for the previous line. Clear the parser
550 * details to parse new line */
551 state->ts_current_line_lf_seen = 0;
552 if (state->ts_current_line_db == 1) {
553 state->ts_current_line_db = 0;
554 SCFree(state->ts_db);
555 state->ts_db = NULL;
4a6908d3 556 state->ts_db_len = 0;
88115902 557 state->current_line = NULL;
4a6908d3 558 state->current_line_len = 0;
88115902 559 }
576ec7da 560 }
576ec7da 561
88115902 562 uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
576ec7da 563
88115902 564 if (lf_idx == NULL) {
5311cd48
AS
565 /* fragmented lines. Decoder event for special cases. Not all
566 * fragmented lines should be treated as a possible evasion
567 * attempt. With multi payload smtp chunks we can have valid
568 * cases of fragmentation. But within the same segment chunk
569 * if we see fragmentation then it's definitely something you
570 * should alert about */
88115902 571 if (state->ts_current_line_db == 0) {
88115902
AS
572 state->ts_db = SCMalloc(state->input_len);
573 if (state->ts_db == NULL) {
574 return -1;
575 }
4a6908d3 576 state->ts_current_line_db = 1;
88115902
AS
577 memcpy(state->ts_db, state->input, state->input_len);
578 state->ts_db_len = state->input_len;
579 } else {
1f07d152
EL
580 ptmp = SCRealloc(state->ts_db,
581 (state->ts_db_len + state->input_len));
582 if (ptmp == NULL) {
583 SCFree(state->ts_db);
584 state->ts_db = NULL;
585 state->ts_db_len = 0;
88115902
AS
586 return -1;
587 }
1f07d152
EL
588 state->ts_db = ptmp;
589
88115902
AS
590 memcpy(state->ts_db + state->ts_db_len,
591 state->input, state->input_len);
592 state->ts_db_len += state->input_len;
593 } /* else */
594 state->input += state->input_len;
595 state->input_len = 0;
596
597 return -1;
4a6908d3 598
576ec7da 599 } else {
88115902
AS
600 state->ts_current_line_lf_seen = 1;
601
4a6908d3 602 if (state->ts_current_line_db == 1) {
1f07d152
EL
603 ptmp = SCRealloc(state->ts_db,
604 (state->ts_db_len + (lf_idx + 1 - state->input)));
605 if (ptmp == NULL) {
606 SCFree(state->ts_db);
607 state->ts_db = NULL;
608 state->ts_db_len = 0;
4a6908d3
AS
609 return -1;
610 }
1f07d152
EL
611 state->ts_db = ptmp;
612
4a6908d3
AS
613 memcpy(state->ts_db + state->ts_db_len,
614 state->input, (lf_idx + 1 - state->input));
615 state->ts_db_len += (lf_idx + 1 - state->input);
616
617 if (state->ts_db_len > 1 &&
618 state->ts_db[state->ts_db_len - 2] == 0x0D) {
619 state->ts_db_len -= 2;
620 state->current_line_delimiter_len = 2;
88115902 621 } else {
4a6908d3
AS
622 state->ts_db_len -= 1;
623 state->current_line_delimiter_len = 1;
88115902 624 }
576ec7da 625
4a6908d3
AS
626 state->current_line = state->ts_db;
627 state->current_line_len = state->ts_db_len;
628
88115902 629 } else {
4a6908d3
AS
630 state->current_line = state->input;
631 state->current_line_len = lf_idx - state->input;
632
633 if (state->input != lf_idx &&
634 *(lf_idx - 1) == 0x0D) {
635 state->current_line_len--;
636 state->current_line_delimiter_len = 2;
88115902 637 } else {
4a6908d3 638 state->current_line_delimiter_len = 1;
88115902 639 }
4a6908d3 640 }
88115902
AS
641
642 state->input_len -= (lf_idx - state->input) + 1;
4a6908d3 643 state->input = (lf_idx + 1);
88115902
AS
644
645 return 0;
4a6908d3 646 }
88115902
AS
647
648 /* toclient */
576ec7da 649 } else {
88115902
AS
650 if (state->tc_current_line_lf_seen == 1) {
651 /* we have seen the lf for the previous line. Clear the parser
652 * details to parse new line */
653 state->tc_current_line_lf_seen = 0;
654 if (state->tc_current_line_db == 1) {
655 state->tc_current_line_db = 0;
656 SCFree(state->tc_db);
657 state->tc_db = NULL;
4a6908d3 658 state->tc_db_len = 0;
88115902 659 state->current_line = NULL;
4a6908d3 660 state->current_line_len = 0;
88115902
AS
661 }
662 }
663
664 uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
665
666 if (lf_idx == NULL) {
5311cd48
AS
667 /* fragmented lines. Decoder event for special cases. Not all
668 * fragmented lines should be treated as a possible evasion
669 * attempt. With multi payload smtp chunks we can have valid
670 * cases of fragmentation. But within the same segment chunk
671 * if we see fragmentation then it's definitely something you
672 * should alert about */
88115902 673 if (state->tc_current_line_db == 0) {
88115902
AS
674 state->tc_db = SCMalloc(state->input_len);
675 if (state->tc_db == NULL) {
576ec7da
AS
676 return -1;
677 }
4a6908d3 678 state->tc_current_line_db = 1;
88115902
AS
679 memcpy(state->tc_db, state->input, state->input_len);
680 state->tc_db_len = state->input_len;
576ec7da 681 } else {
1f07d152
EL
682 ptmp = SCRealloc(state->tc_db,
683 (state->tc_db_len + state->input_len));
684 if (ptmp == NULL) {
685 SCFree(state->tc_db);
686 state->tc_db = NULL;
687 state->tc_db_len = 0;
88115902
AS
688 return -1;
689 }
1f07d152
EL
690 state->tc_db = ptmp;
691
88115902
AS
692 memcpy(state->tc_db + state->tc_db_len,
693 state->input, state->input_len);
694 state->tc_db_len += state->input_len;
695 } /* else */
696 state->input += state->input_len;
697 state->input_len = 0;
576ec7da 698
88115902 699 return -1;
4a6908d3 700
576ec7da 701 } else {
88115902
AS
702 state->tc_current_line_lf_seen = 1;
703
4a6908d3 704 if (state->tc_current_line_db == 1) {
1f07d152
EL
705 ptmp = SCRealloc(state->tc_db,
706 (state->tc_db_len + (lf_idx + 1 - state->input)));
707 if (ptmp == NULL) {
708 SCFree(state->tc_db);
709 state->tc_db = NULL;
710 state->tc_db_len = 0;
4a6908d3
AS
711 return -1;
712 }
1f07d152
EL
713 state->tc_db = ptmp;
714
4a6908d3
AS
715 memcpy(state->tc_db + state->tc_db_len,
716 state->input, (lf_idx + 1 - state->input));
717 state->tc_db_len += (lf_idx + 1 - state->input);
718
719 if (state->tc_db_len > 1 &&
720 state->tc_db[state->tc_db_len - 2] == 0x0D) {
721 state->tc_db_len -= 2;
722 state->current_line_delimiter_len = 2;
88115902 723 } else {
4a6908d3
AS
724 state->tc_db_len -= 1;
725 state->current_line_delimiter_len = 1;
576ec7da 726 }
88115902 727
4a6908d3
AS
728 state->current_line = state->tc_db;
729 state->current_line_len = state->tc_db_len;
730
576ec7da 731 } else {
4a6908d3
AS
732 state->current_line = state->input;
733 state->current_line_len = lf_idx - state->input;
734
735 if (state->input != lf_idx &&
736 *(lf_idx - 1) == 0x0D) {
737 state->current_line_len--;
738 state->current_line_delimiter_len = 2;
88115902 739 } else {
4a6908d3 740 state->current_line_delimiter_len = 1;
88115902 741 }
4a6908d3 742 }
576ec7da 743
88115902 744 state->input_len -= (lf_idx - state->input) + 1;
4a6908d3 745 state->input = (lf_idx + 1);
88115902
AS
746
747 return 0;
748 } /* else - if (lf_idx == NULL) */
749 }
576ec7da 750
576ec7da
AS
751}
752
5311cd48 753static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state, Flow *f)
576ec7da 754{
7b0f261f 755 SCEnter();
1f07d152 756 void *ptmp;
7b0f261f 757
576ec7da 758 if (state->cmds_cnt >= state->cmds_buffer_len) {
bc5c9f4a
VJ
759 int increment = SMTP_COMMAND_BUFFER_STEPS;
760 if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) {
761 increment = USHRT_MAX - state->cmds_buffer_len;
762 }
763
1f07d152
EL
764 ptmp = SCRealloc(state->cmds,
765 sizeof(uint8_t) * (state->cmds_buffer_len + increment));
766 if (ptmp == NULL) {
767 SCFree(state->cmds);
768 state->cmds = NULL;
769 SCLogDebug("SCRealloc failure");
576ec7da
AS
770 return -1;
771 }
1f07d152
EL
772 state->cmds = ptmp;
773
bc5c9f4a 774 state->cmds_buffer_len += increment;
576ec7da
AS
775 }
776 if (state->cmds_cnt >= 1 &&
777 ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) ||
778 (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) {
779 /* decoder event */
d209699a 780 SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE);
576ec7da
AS
781 /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP,
782 * STARTTLS as the last command in pipelined mode */
783 }
bc5c9f4a
VJ
784
785 /** \todo decoder event */
7b0f261f
VJ
786 if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) {
787 SCLogDebug("command buffer overflow");
bc5c9f4a 788 return -1;
7b0f261f 789 }
bc5c9f4a 790
576ec7da
AS
791 state->cmds[state->cmds_cnt] = command;
792 state->cmds_cnt++;
793
794 return 0;
795}
796
d3ca65de 797static int SMTPProcessCommandBDAT(SMTPState *state, Flow *f,
9634e60e 798 AppLayerParserState *pstate)
d3ca65de 799{
7b0f261f
VJ
800 SCEnter();
801
d3ca65de
AS
802 state->bdat_chunk_idx += (state->current_line_len +
803 state->current_line_delimiter_len);
804 if (state->bdat_chunk_idx > state->bdat_chunk_len) {
805 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
806 /* decoder event */
d209699a 807 SMTPSetEvent(state, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED);
7b0f261f 808 SCReturnInt(-1);
d3ca65de
AS
809 } else if (state->bdat_chunk_idx == state->bdat_chunk_len) {
810 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
811 }
812
7b0f261f 813 SCReturnInt(0);
d3ca65de
AS
814}
815
576ec7da 816static int SMTPProcessCommandDATA(SMTPState *state, Flow *f,
9634e60e 817 AppLayerParserState *pstate)
576ec7da 818{
7b0f261f
VJ
819 SCEnter();
820
576ec7da
AS
821 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
822 /* looks like are still waiting for a confirmination from the server */
823 return 0;
824 }
825
826 if (state->current_line_len == 1 && state->current_line[0] == '.') {
827 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
828 /* kinda like a hack. The mail sent in DATA mode, would be
829 * acknowledged with a reply. We insert a dummy command to
830 * the command buffer to be used by the reply handler to match
831 * the reply received */
5311cd48 832 SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f);
c2dc6867 833
202b11c0 834 if (smtp_config.decode_mime && state->curr_tx->mime_state != NULL) {
c2dc6867 835 /* Complete parsing task */
56b74c8b 836 int ret = MimeDecParseComplete(state->curr_tx->mime_state);
c2dc6867
DA
837 if (ret != MIME_DEC_OK) {
838
d209699a 839 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED);
c2dc6867
DA
840 SCLogDebug("MimeDecParseComplete() function failed");
841 }
842
843 /* Generate decoder events */
56b74c8b 844 MimeDecEntity *msg = state->curr_tx->mime_state->msg;
c2dc6867 845 if (msg->anomaly_flags & ANOM_INVALID_BASE64) {
d209699a 846 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64);
c2dc6867
DA
847 }
848 if (msg->anomaly_flags & ANOM_INVALID_QP) {
d209699a 849 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP);
c2dc6867
DA
850 }
851 if (msg->anomaly_flags & ANOM_LONG_LINE) {
d209699a 852 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE);
c2dc6867
DA
853 }
854 if (msg->anomaly_flags & ANOM_LONG_ENC_LINE) {
d209699a 855 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE);
c2dc6867
DA
856 }
857 if (msg->anomaly_flags & ANOM_LONG_HEADER_NAME) {
d209699a 858 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME);
c2dc6867
DA
859 }
860 if (msg->anomaly_flags & ANOM_LONG_HEADER_VALUE) {
d209699a 861 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE);
c2dc6867
DA
862 }
863 if (msg->anomaly_flags & ANOM_MALFORMED_MSG) {
d209699a 864 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG);
c2dc6867 865 }
6d170cad
VJ
866 if (msg->anomaly_flags & ANOM_LONG_BOUNDARY) {
867 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG);
868 }
c2dc6867 869 }
d209699a
VJ
870 state->curr_tx->done = 1;
871 SCLogDebug("marked tx as done");
c2dc6867
DA
872 }
873
874 /* If DATA, then parse out a MIME message */
875 if (state->current_command == SMTP_COMMAND_DATA &&
876 (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
877
d209699a 878 if (smtp_config.decode_mime && state->curr_tx->mime_state) {
106bbc78 879 int ret = MimeDecParseLine((const uint8_t *) state->current_line,
2ecab3f7
EL
880 state->current_line_len, state->current_line_delimiter_len,
881 state->curr_tx->mime_state);
c2dc6867
DA
882 if (ret != MIME_DEC_OK) {
883 SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret);
884 }
885 }
576ec7da
AS
886 }
887
888 return 0;
889}
890
891static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f,
9634e60e 892 AppLayerParserState *pstate)
576ec7da
AS
893{
894 return 0;
895}
896
897static int SMTPProcessReply(SMTPState *state, Flow *f,
eec66c7b
VJ
898 AppLayerParserState *pstate,
899 SMTPThreadCtx *td)
576ec7da 900{
7b0f261f
VJ
901 SCEnter();
902
576ec7da
AS
903 uint64_t reply_code = 0;
904
576ec7da
AS
905 /* the reply code has to contain at least 3 bytes, to hold the 3 digit
906 * reply code */
907 if (state->current_line_len < 3) {
908 /* decoder event */
d209699a 909 SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
576ec7da
AS
910 return -1;
911 }
912
913 if (state->current_line_len >= 4) {
914 if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
915 if (state->current_line[3] != '-') {
916 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
917 }
918 } else {
919 if (state->current_line[3] == '-') {
920 state->parser_state |= SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
921 }
922 }
923 } else {
924 if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
925 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
926 }
927 }
928
4d38a571
AS
929 /* I don't like this pmq reset here. We'll devise a method later, that
930 * should make the use of the mpm very efficient */
eec66c7b
VJ
931 PmqReset(td->pmq);
932 int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, td->smtp_mpm_thread_ctx,
933 td->pmq, state->current_line,
4d38a571
AS
934 3);
935 if (mpm_cnt == 0) {
936 /* set decoder event - reply code invalid */
d209699a 937 SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
7b0f261f
VJ
938 SCLogDebug("invalid reply code %02x %02x %02x",
939 state->current_line[0], state->current_line[1], state->current_line[2]);
940 SCReturnInt(-1);
4d38a571 941 }
eec66c7b 942 reply_code = smtp_reply_map[td->pmq->rule_id_array[0]].enum_value;
4d38a571
AS
943
944 if (state->cmds_idx == state->cmds_cnt) {
0d7159b5 945 if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1291250c
MA
946 /* the first server reply can be a multiline message. Let's
947 * flag the fact that we have seen the first reply only at the end
948 * of a multiline reply
949 */
950 if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY))
951 state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN;
0d7159b5
AS
952 if (reply_code == SMTP_REPLY_220)
953 SCReturnInt(0);
26084182 954 else {
d209699a 955 SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
26084182
VJ
956 SCReturnInt(0);
957 }
4d38a571 958 } else {
0d7159b5
AS
959 /* decoder event - unable to match reply with request */
960 SCLogDebug("unable to match reply with request");
26084182 961 SCReturnInt(0);
576ec7da
AS
962 }
963 }
964
95fa5ae1
VJ
965 if (state->cmds_cnt == 0) {
966 /* reply but not a command we have stored, fall through */
967 } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_STARTTLS) {
4d38a571 968 if (reply_code == SMTP_REPLY_220) {
576ec7da
AS
969 /* we are entering STARRTTLS data mode */
970 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
8527b8e0 971 AppLayerParserStateSetFlag(pstate,
429c6388
AS
972 APP_LAYER_PARSER_NO_INSPECTION |
973 APP_LAYER_PARSER_NO_REASSEMBLY);
576ec7da
AS
974 } else {
975 /* decoder event */
d209699a 976 SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED);
576ec7da
AS
977 }
978 } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_DATA) {
4d38a571 979 if (reply_code == SMTP_REPLY_354) {
576ec7da
AS
980 /* Next comes the mail for the DATA command in toserver direction */
981 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
982 } else {
983 /* decoder event */
d209699a 984 SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED);
576ec7da
AS
985 }
986 } else {
4d38a571
AS
987 /* we don't care for any other command for now */
988 /* check if reply falls in the valid list of replies for SMTP. If not
989 * decoder event */
576ec7da
AS
990 }
991
4d38a571 992 /* if it is a multi-line reply, we need to move the index only once for all
576ec7da
AS
993 * the line of the reply. We unset the multiline flag on the last
994 * line of the multiline reply, following which we increment the index */
995 if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) {
996 state->cmds_idx++;
997 }
998
999 /* if we have matched all the buffered commands, reset the cnt and index */
1000 if (state->cmds_idx == state->cmds_cnt) {
1001 state->cmds_cnt = 0;
1002 state->cmds_idx = 0;
1003 }
1004
1005 return 0;
1006}
1007
d3ca65de
AS
1008static int SMTPParseCommandBDAT(SMTPState *state)
1009{
7b0f261f
VJ
1010 SCEnter();
1011
d3ca65de
AS
1012 int i = 4;
1013 while (i < state->current_line_len) {
1014 if (state->current_line[i] != ' ') {
1015 break;
1016 }
1017 i++;
1018 }
1019 if (i == 4) {
1020 /* decoder event */
1021 return -1;
1022 }
1023 if (i == state->current_line_len) {
1024 /* decoder event */
1025 return -1;
1026 }
25638832 1027 char *endptr = NULL;
d3ca65de
AS
1028 state->bdat_chunk_len = strtoul((const char *)state->current_line + i,
1029 (char **)&endptr, 10);
25638832 1030 if ((uint8_t *)endptr == state->current_line + i) {
d3ca65de
AS
1031 /* decoder event */
1032 return -1;
1033 }
1034
1035 return 0;
1036}
1037
7bca8268
EL
1038static int SMTPParseCommandWithParam(SMTPState *state, uint8_t prefix_len, uint8_t **target, uint16_t *target_len)
1039{
1040 int i = prefix_len + 1;
1041 int spc_i = 0;
1042
1043 while (i < state->current_line_len) {
1044 if (state->current_line[i] != ' ') {
1045 break;
1046 }
1047 i++;
1048 }
1049
1050 /* rfc1870: with the size extension the mail from can be followed by an option.
1051 We use the space separator to detect it. */
1052 spc_i = i;
1053 while (spc_i < state->current_line_len) {
1054 if (state->current_line[spc_i] == ' ') {
1055 break;
1056 }
1057 spc_i++;
1058 }
1059
7bca8268
EL
1060 *target = SCMalloc(spc_i - i + 1);
1061 if (*target == NULL)
1062 return -1;
1063 memcpy(*target, state->current_line + i, spc_i - i);
1064 (*target)[spc_i - i] = '\0';
1065 *target_len = spc_i - i;
1066
1067 return 0;
7bca8268
EL
1068}
1069
1070static int SMTPParseCommandHELO(SMTPState *state)
1071{
10e2e2a8
EL
1072 if (state->helo) {
1073 SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1074 return 0;
1075 }
7bca8268
EL
1076 return SMTPParseCommandWithParam(state, 4, &state->helo, &state->helo_len);
1077}
1078
1079static int SMTPParseCommandMAILFROM(SMTPState *state)
1080{
10e2e2a8
EL
1081 if (state->curr_tx->mail_from) {
1082 SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1083 return 0;
1084 }
7bca8268
EL
1085 return SMTPParseCommandWithParam(state, 9,
1086 &state->curr_tx->mail_from,
1087 &state->curr_tx->mail_from_len);
1088}
1089
752fdba9
EL
1090static int SMTPParseCommandRCPTTO(SMTPState *state)
1091{
1092 uint8_t *rcptto;
1093 uint16_t rcptto_len;
1094
1095 if (SMTPParseCommandWithParam(state, 7, &rcptto, &rcptto_len) == 0) {
1096 SMTPString *rcptto_str = SMTPStringAlloc();
1097 if (rcptto_str) {
1098 rcptto_str->str = rcptto;
1099 rcptto_str->len = rcptto_len;
1100 TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next);
1101 } else {
1102 SCFree(rcptto);
1103 return -1;
1104 }
1105 } else {
1106 return -1;
1107 }
1108 return 0;
1109}
1110
7c3b22da
VJ
1111/* consider 'rset' and 'quit' to be part of the existing state */
1112static int NoNewTx(SMTPState *state)
1113{
1114 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1115 if (state->current_line_len >= 4 &&
1116 SCMemcmpLowercase("rset", state->current_line, 4) == 0) {
1117 return 1;
1118 } else if (state->current_line_len >= 4 &&
1119 SCMemcmpLowercase("quit", state->current_line, 4) == 0) {
1120 return 1;
1121 }
1122 }
1123 return 0;
1124}
1125
576ec7da 1126static int SMTPProcessRequest(SMTPState *state, Flow *f,
9634e60e 1127 AppLayerParserState *pstate)
576ec7da 1128{
7b0f261f 1129 SCEnter();
d209699a
VJ
1130 SMTPTransaction *tx = state->curr_tx;
1131
7c3b22da 1132 if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state))) {
d209699a
VJ
1133 tx = SMTPTransactionCreate();
1134 if (tx == NULL)
1135 return -1;
1136 state->curr_tx = tx;
1137 TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1138 tx->tx_id = state->tx_cnt++;
1139 }
7b0f261f 1140
0d7159b5 1141 if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
d209699a 1142 SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE);
0d7159b5
AS
1143 }
1144
576ec7da
AS
1145 /* there are 2 commands that can push it into this COMMAND_DATA mode -
1146 * STARTTLS and DATA */
1147 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
d3ca65de
AS
1148 int r = 0;
1149
576ec7da
AS
1150 if (state->current_line_len >= 8 &&
1151 SCMemcmpLowercase("starttls", state->current_line, 8) == 0) {
1152 state->current_command = SMTP_COMMAND_STARTTLS;
1153 } else if (state->current_line_len >= 4 &&
1154 SCMemcmpLowercase("data", state->current_line, 4) == 0) {
1155 state->current_command = SMTP_COMMAND_DATA;
c2dc6867 1156 if (smtp_config.decode_mime) {
5dbedbfa
EL
1157 if (tx->mime_state) {
1158 /* We have 2 chained mails and did not detect the end
1159 * of first one. So we start a new transaction. */
1160 tx->mime_state->state_flag = PARSE_ERROR;
1161 SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1162 tx = SMTPTransactionCreate();
1163 if (tx == NULL)
1164 return -1;
1165 state->curr_tx = tx;
1166 TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1167 tx->tx_id = state->tx_cnt++;
1168 }
d2657bec 1169 tx->mime_state = MimeDecInitParser(f, SMTPProcessDataChunk);
56b74c8b 1170 if (tx->mime_state == NULL) {
c2dc6867
DA
1171 SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to "
1172 "allocate data");
1173 return MIME_DEC_ERR_MEM;
1174 }
1175
1176 /* Add new MIME message to end of list */
56b74c8b
VJ
1177 if (tx->msg_head == NULL) {
1178 tx->msg_head = tx->mime_state->msg;
1179 tx->msg_tail = tx->mime_state->msg;
c2dc6867
DA
1180 }
1181 else {
56b74c8b
VJ
1182 tx->msg_tail->next = tx->mime_state->msg;
1183 tx->msg_tail = tx->mime_state->msg;
c2dc6867
DA
1184 }
1185 }
1186
d3ca65de
AS
1187 } else if (state->current_line_len >= 4 &&
1188 SCMemcmpLowercase("bdat", state->current_line, 4) == 0) {
1189 r = SMTPParseCommandBDAT(state);
7b0f261f
VJ
1190 if (r == -1) {
1191 SCReturnInt(-1);
1192 }
d3ca65de
AS
1193 state->current_command = SMTP_COMMAND_BDAT;
1194 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
7bca8268
EL
1195 } else if (state->current_line_len >= 4 &&
1196 ((SCMemcmpLowercase("helo", state->current_line, 4) == 0) ||
1197 SCMemcmpLowercase("ehlo", state->current_line, 4) == 0)) {
1198 r = SMTPParseCommandHELO(state);
1199 if (r == -1) {
1200 SCReturnInt(-1);
1201 }
1202 state->current_command = SMTP_COMMAND_OTHER_CMD;
1203 } else if (state->current_line_len >= 9 &&
1204 SCMemcmpLowercase("mail from", state->current_line, 9) == 0) {
1205 r = SMTPParseCommandMAILFROM(state);
1206 if (r == -1) {
1207 SCReturnInt(-1);
1208 }
1209 state->current_command = SMTP_COMMAND_OTHER_CMD;
752fdba9
EL
1210 } else if (state->current_line_len >= 7 &&
1211 SCMemcmpLowercase("rcpt to", state->current_line, 7) == 0) {
1212 r = SMTPParseCommandRCPTTO(state);
1213 if (r == -1) {
1214 SCReturnInt(-1);
1215 }
1216 state->current_command = SMTP_COMMAND_OTHER_CMD;
576ec7da
AS
1217 } else {
1218 state->current_command = SMTP_COMMAND_OTHER_CMD;
1219 }
1220
1221 /* Every command is inserted into a command buffer, to be matched
1222 * against reply(ies) sent by the server */
1223 if (SMTPInsertCommandIntoCommandBuffer(state->current_command,
5311cd48 1224 state, f) == -1) {
7b0f261f 1225 SCReturnInt(-1);
576ec7da 1226 }
d3ca65de 1227
7b0f261f 1228 SCReturnInt(r);
576ec7da
AS
1229 }
1230
1231 switch (state->current_command) {
1232 case SMTP_COMMAND_STARTTLS:
1233 return SMTPProcessCommandSTARTTLS(state, f, pstate);
1234
1235 case SMTP_COMMAND_DATA:
1236 return SMTPProcessCommandDATA(state, f, pstate);
1237
d3ca65de
AS
1238 case SMTP_COMMAND_BDAT:
1239 return SMTPProcessCommandBDAT(state, f, pstate);
1240
576ec7da
AS
1241 default:
1242 /* we have nothing to do with any other command at this instant.
1243 * Just let it go through */
7b0f261f 1244 SCReturnInt(0);
576ec7da
AS
1245 }
1246}
1247
88115902 1248static int SMTPParse(int direction, Flow *f, SMTPState *state,
9634e60e 1249 AppLayerParserState *pstate, uint8_t *input,
997eaf42 1250 uint32_t input_len,
eec66c7b 1251 SMTPThreadCtx *thread_data)
576ec7da 1252{
7b0f261f
VJ
1253 SCEnter();
1254
4e7cb7b8
VJ
1255 if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
1256 SCReturnInt(1);
f4f53924
VJ
1257 } else if (input == NULL || input_len == 0) {
1258 SCReturnInt(-1);
4e7cb7b8
VJ
1259 }
1260
576ec7da
AS
1261 state->input = input;
1262 state->input_len = input_len;
88115902 1263 state->direction = direction;
576ec7da 1264
87599bc7
AS
1265 /* toserver */
1266 if (direction == 0) {
1267 while (SMTPGetLine(state) >= 0) {
d3ca65de 1268 if (SMTPProcessRequest(state, f, pstate) == -1)
7b0f261f 1269 SCReturnInt(-1);
87599bc7 1270 }
88115902 1271
87599bc7
AS
1272 /* toclient */
1273 } else {
1274 while (SMTPGetLine(state) >= 0) {
eec66c7b 1275 if (SMTPProcessReply(state, f, pstate, thread_data) == -1)
7b0f261f 1276 SCReturnInt(-1);
88115902 1277 }
576ec7da
AS
1278 }
1279
7b0f261f 1280 SCReturnInt(0);
576ec7da
AS
1281}
1282
88115902 1283static int SMTPParseClientRecord(Flow *f, void *alstate,
9634e60e 1284 AppLayerParserState *pstate,
576ec7da 1285 uint8_t *input, uint32_t input_len,
429c6388 1286 void *local_data)
576ec7da 1287{
7b0f261f
VJ
1288 SCEnter();
1289
88115902 1290 /* first arg 0 is toserver */
429c6388 1291 return SMTPParse(0, f, alstate, pstate, input, input_len, local_data);
88115902 1292}
576ec7da 1293
88115902 1294static int SMTPParseServerRecord(Flow *f, void *alstate,
9634e60e 1295 AppLayerParserState *pstate,
88115902 1296 uint8_t *input, uint32_t input_len,
429c6388 1297 void *local_data)
88115902 1298{
7b0f261f
VJ
1299 SCEnter();
1300
88115902 1301 /* first arg 1 is toclient */
429c6388 1302 return SMTPParse(1, f, alstate, pstate, input, input_len, local_data);
576ec7da
AS
1303
1304 return 0;
1305}
1306
1307/**
1308 * \internal
1309 * \brief Function to allocate SMTP state memory.
1310 */
d2657bec 1311void *SMTPStateAlloc(void)
576ec7da
AS
1312{
1313 SMTPState *smtp_state = SCMalloc(sizeof(SMTPState));
e176be6f 1314 if (unlikely(smtp_state == NULL))
576ec7da
AS
1315 return NULL;
1316 memset(smtp_state, 0, sizeof(SMTPState));
1317
1318 smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
1319 SMTP_COMMAND_BUFFER_STEPS);
1320 if (smtp_state->cmds == NULL) {
1321 SCFree(smtp_state);
1322 return NULL;
1323 }
1324 smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS;
1325
56b74c8b
VJ
1326 TAILQ_INIT(&smtp_state->tx_list);
1327
997eaf42
AS
1328 return smtp_state;
1329}
1330
752fdba9
EL
1331static SMTPString *SMTPStringAlloc(void)
1332{
1333 SMTPString *smtp_string = SCMalloc(sizeof(SMTPString));
1334 if (unlikely(smtp_string == NULL))
1335 return NULL;
1336 memset(smtp_string, 0, sizeof(SMTPString));
1337
1338 return smtp_string;
1339}
1340
1341
1342static void SMTPStringFree(SMTPString *str)
1343{
1344 if (str->str) {
1345 SCFree(str->str);
1346 }
1347 SCFree(str);
1348}
1349
997eaf42
AS
1350static void *SMTPLocalStorageAlloc(void)
1351{
1352 /* needed by the mpm */
eec66c7b
VJ
1353 SMTPThreadCtx *td = SCCalloc(1, sizeof(*td));
1354 if (td == NULL) {
1355 exit(EXIT_FAILURE);
1356 }
1357
1358 td->pmq = SCCalloc(1, sizeof(*td->pmq));
1359 if (td->pmq == NULL) {
4d38a571
AS
1360 exit(EXIT_FAILURE);
1361 }
eec66c7b 1362 PmqSetup(td->pmq);
4d38a571 1363
eec66c7b
VJ
1364 td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
1365 if (unlikely(td->smtp_mpm_thread_ctx == NULL)) {
1366 exit(EXIT_FAILURE);
1367 }
1368 MpmInitThreadCtx(td->smtp_mpm_thread_ctx, SMTP_MPM);
1369 return td;
997eaf42
AS
1370}
1371
eec66c7b 1372static void SMTPLocalStorageFree(void *ptr)
997eaf42 1373{
eec66c7b
VJ
1374 SMTPThreadCtx *td = ptr;
1375 if (td != NULL) {
1376 if (td->pmq != NULL) {
1377 PmqFree(td->pmq);
1378 SCFree(td->pmq);
1379 }
1380
1381 if (td->smtp_mpm_thread_ctx != NULL) {
1382 mpm_table[SMTP_MPM].DestroyThreadCtx(smtp_mpm_ctx, td->smtp_mpm_thread_ctx);
1383 SCFree(td->smtp_mpm_thread_ctx);
1384 }
1385
1386 SCFree(td);
997eaf42
AS
1387 }
1388
1389 return;
576ec7da
AS
1390}
1391
56b74c8b
VJ
1392static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
1393{
1394 if (tx->mime_state != NULL) {
1395 MimeDecDeInitParser(tx->mime_state);
1396 }
d209699a
VJ
1397 /* Free list of MIME message recursively */
1398 MimeDecFreeEntity(tx->msg_head);
1399
7b818494 1400 if (tx->decoder_events != NULL)
d209699a 1401 AppLayerDecoderEventsFreeEvents(&tx->decoder_events);
7b818494 1402
e984a572
VJ
1403 if (tx->de_state != NULL)
1404 DetectEngineStateFree(tx->de_state);
7bca8268
EL
1405
1406 if (tx->mail_from)
1407 SCFree(tx->mail_from);
1408
752fdba9
EL
1409 SMTPString *str = NULL;
1410 while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) {
1411 TAILQ_REMOVE(&tx->rcpt_to_list, str, next);
1412 SMTPStringFree(str);
1413 }
d209699a
VJ
1414#if 0
1415 if (tx->decoder_events->cnt <= smtp_state->events)
1416 smtp_state->events -= tx->decoder_events->cnt;
1417 else
1418 smtp_state->events = 0;
1419#endif
56b74c8b
VJ
1420 SCFree(tx);
1421}
1422
576ec7da
AS
1423/**
1424 * \internal
1425 * \brief Function to free SMTP state memory.
1426 */
1427static void SMTPStateFree(void *p)
1428{
1429 SMTPState *smtp_state = (SMTPState *)p;
1430
1431 if (smtp_state->cmds != NULL) {
1432 SCFree(smtp_state->cmds);
1433 }
88115902
AS
1434 if (smtp_state->ts_current_line_db) {
1435 SCFree(smtp_state->ts_db);
1436 }
1437 if (smtp_state->tc_current_line_db) {
1438 SCFree(smtp_state->tc_db);
1439 }
576ec7da 1440
7bca8268
EL
1441 if (smtp_state->helo) {
1442 SCFree(smtp_state->helo);
1443 }
1444
c2dc6867 1445 FileContainerFree(smtp_state->files_ts);
56b74c8b
VJ
1446
1447 SMTPTransaction *tx = NULL;
1448 while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
56b74c8b
VJ
1449 TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1450 SMTPTransactionFree(tx, smtp_state);
1451 }
c2dc6867 1452
576ec7da
AS
1453 SCFree(smtp_state);
1454
1455 return;
1456}
1457
4d38a571
AS
1458static void SMTPSetMpmState(void)
1459{
1460 smtp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
e176be6f 1461 if (unlikely(smtp_mpm_ctx == NULL)) {
4d38a571
AS
1462 exit(EXIT_FAILURE);
1463 }
1464 memset(smtp_mpm_ctx, 0, sizeof(MpmCtx));
a49cbf8a 1465 MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
4d38a571 1466
4d38a571
AS
1467 uint32_t i = 0;
1468 for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
1469 SCEnumCharMap *map = &smtp_reply_map[i];
a49cbf8a
AS
1470 /* The third argument is 3, because reply code is always 3 bytes. */
1471 MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3,
1472 0 /* defunct */, 0 /* defunct */,
cd8283bb 1473 i /* pattern id */, i /* rule id */ , 0 /* no flags */);
4d38a571
AS
1474 }
1475
1476 mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx);
68ddcdcc 1477
4d38a571
AS
1478}
1479
7a0dbc6f
JV
1480static void SMTPFreeMpmState(void)
1481{
7a0dbc6f
JV
1482 if (smtp_mpm_ctx != NULL) {
1483 mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx);
eec66c7b 1484 SCFree(smtp_mpm_ctx);
7a0dbc6f
JV
1485 smtp_mpm_ctx = NULL;
1486 }
1487}
1488
5e2d9dbd
AS
1489int SMTPStateGetEventInfo(const char *event_name,
1490 int *event_id, AppLayerEventType *event_type)
1491{
1492 *event_id = SCMapEnumNameToValue(event_name, smtp_decoder_event_table);
1493 if (*event_id == -1) {
1494 SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
1495 "smtp's enum map table.", event_name);
1496 /* yes this is fatal */
1497 return -1;
1498 }
1499
d209699a 1500 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
5e2d9dbd
AS
1501
1502 return 0;
1503}
1504
429c6388
AS
1505static int SMTPRegisterPatternsForProtocolDetection(void)
1506{
1507 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP,
1508 "EHLO", 4, 0, STREAM_TOSERVER) < 0)
1509 {
1510 return -1;
1511 }
1512 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP,
1513 "HELO", 4, 0, STREAM_TOSERVER) < 0)
1514 {
1515 return -1;
1516 }
1517 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP,
1518 "QUIT", 4, 0, STREAM_TOSERVER) < 0)
1519 {
1520 return -1;
1521 }
1522
1523 return 0;
1524}
1525
56b74c8b
VJ
1526static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
1527{
56b74c8b
VJ
1528 SMTPState *smtp_state = state;
1529 SMTPTransaction *tx = NULL;
1530 TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1531 if (tx_id < tx->tx_id)
1532 break;
1533 else if (tx_id > tx->tx_id)
1534 continue;
1535
1536 if (tx == smtp_state->curr_tx)
1537 smtp_state->curr_tx = NULL;
56b74c8b
VJ
1538 TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1539 SMTPTransactionFree(tx, state);
1540 break;
1541 }
1542
1543
1544}
1545
f32d79df 1546/** \retval cnt highest tx id */
56b74c8b
VJ
1547static uint64_t SMTPStateGetTxCnt(void *state)
1548{
1549 uint64_t cnt = 0;
1550 SMTPState *smtp_state = state;
1551 if (smtp_state) {
f32d79df 1552 cnt = smtp_state->tx_cnt;
56b74c8b
VJ
1553 }
1554 SCLogDebug("returning %"PRIu64, cnt);
1555 return cnt;
1556}
1557
1558static void *SMTPStateGetTx(void *state, uint64_t id)
1559{
1560 SMTPState *smtp_state = state;
1561 if (smtp_state) {
1562 SMTPTransaction *tx = NULL;
1563
1564 if (smtp_state->curr_tx == NULL)
1565 return NULL;
1566 if (smtp_state->curr_tx->tx_id == id)
1567 return smtp_state->curr_tx;
1568
1569 TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1570 if (tx->tx_id == id)
1571 return tx;
1572 }
1573 }
56b74c8b
VJ
1574 return NULL;
1575
1576}
1577
d484812d
MK
1578static void SMTPStateSetTxLogged(void *state, void *vtx, uint32_t logger)
1579{
1580 SMTPTransaction *tx = vtx;
1581 tx->logged |= logger;
1582}
1583
1584static int SMTPStateGetTxLogged(void *state, void *vtx, uint32_t logger)
1585{
1586 SMTPTransaction *tx = vtx;
1587 if (tx->logged & logger)
1588 return 1;
1589
1590 return 0;
1591}
1592
56b74c8b 1593static int SMTPStateGetAlstateProgressCompletionStatus(uint8_t direction) {
d209699a 1594 return 1;
56b74c8b
VJ
1595}
1596
1597static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
1598{
1599 SMTPTransaction *tx = vtx;
d209699a 1600 return tx->done;
56b74c8b
VJ
1601}
1602
1603static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction)
1604{
1605 if (state == NULL)
1606 return NULL;
1607
1608 SMTPState *smtp_state = (SMTPState *)state;
1609
1610 if (direction & STREAM_TOCLIENT) {
1611 SCReturnPtr(NULL, "FileContainer");
1612 } else {
1613 SCLogDebug("smtp_state->files_ts %p", smtp_state->files_ts);
1614 SCReturnPtr(smtp_state->files_ts, "FileContainer");
1615 }
1616}
1617
08b06bac
VJ
1618static void SMTPStateTruncate(void *state, uint8_t direction)
1619{
1620 FileContainer *fc = SMTPStateGetFiles(state, direction);
1621 if (fc != NULL) {
1622 SCLogDebug("truncating stream, closing files in %s direction (container %p)",
1623 direction & STREAM_TOCLIENT ? "STREAM_TOCLIENT" : "STREAM_TOSERVER", fc);
1624 FileTruncateAllOpenFiles(fc);
1625 }
1626}
1627
d209699a
VJ
1628static AppLayerDecoderEvents *SMTPGetEvents(void *state, uint64_t tx_id)
1629{
1630 SCLogDebug("get SMTP events for TX %"PRIu64, tx_id);
1631
1632 SMTPTransaction *tx = SMTPStateGetTx(state, tx_id);
1633 if (tx != NULL) {
1634 return tx->decoder_events;
1635 }
1636 return NULL;
1637}
1638
e984a572
VJ
1639static DetectEngineState *SMTPGetTxDetectState(void *vtx)
1640{
1641 SMTPTransaction *tx = (SMTPTransaction *)vtx;
1642 return tx->de_state;
1643}
1644
f536099a 1645static int SMTPSetTxDetectState(void *state, void *vtx, DetectEngineState *s)
e984a572
VJ
1646{
1647 SMTPTransaction *tx = (SMTPTransaction *)vtx;
1648 tx->de_state = s;
1649 return 0;
1650}
1651
576ec7da 1652/**
e5c36952 1653 * \brief Register the SMTP Protocol parser.
576ec7da
AS
1654 */
1655void RegisterSMTPParsers(void)
1656{
10966245
AS
1657 char *proto_name = "smtp";
1658
429c6388
AS
1659 if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1660 AppLayerProtoDetectRegisterProtocol(ALPROTO_SMTP, proto_name);
1661 if (SMTPRegisterPatternsForProtocolDetection() < 0 )
1662 return;
ddde572f
AS
1663 } else {
1664 SCLogInfo("Protocol detection and parser disabled for %s protocol.",
1665 proto_name);
1666 return;
1667 }
576ec7da 1668
429c6388
AS
1669 if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
1670 AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
576ec7da 1671
429c6388
AS
1672 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER,
1673 SMTPParseClientRecord);
1674 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT,
1675 SMTPParseServerRecord);
6cb00142 1676
429c6388 1677 AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
d209699a 1678 AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents);
f536099a 1679 AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, NULL,
e984a572 1680 SMTPGetTxDetectState, SMTPSetTxDetectState);
576ec7da 1681
429c6388
AS
1682 AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
1683 SMTPLocalStorageFree);
56b74c8b
VJ
1684
1685 AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
1686 AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetFiles);
1687 AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
1688 AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
1689 AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
d484812d
MK
1690 AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxLogged,
1691 SMTPStateSetTxLogged);
c4b918b6 1692 AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_SMTP,
56b74c8b 1693 SMTPStateGetAlstateProgressCompletionStatus);
08b06bac 1694 AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate);
ddde572f
AS
1695 } else {
1696 SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
1697 "still on.", proto_name);
1698 }
997eaf42 1699
4d38a571
AS
1700 SMTPSetMpmState();
1701
c2dc6867
DA
1702 SMTPConfigure();
1703
9faa4b74 1704#ifdef UNITTESTS
429c6388 1705 AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMTP, SMTPParserRegisterTests);
9faa4b74 1706#endif
576ec7da
AS
1707 return;
1708}
1709
7a0dbc6f
JV
1710/**
1711 * \brief Free memory allocated for global SMTP parser state.
1712 */
1713void SMTPParserCleanup(void)
1714{
1715 SMTPFreeMpmState();
1716}
1717
576ec7da
AS
1718/***************************************Unittests******************************/
1719
87599bc7
AS
1720#ifdef UNITTESTS
1721
e43ce0a9
VJ
1722static void SMTPTestInitConfig(void)
1723{
1724 MimeDecSetConfig(&smtp_config.mime_config);
1725
1726 smtp_config.content_limit = FILEDATA_CONTENT_LIMIT;
1727 smtp_config.content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW;
1728 smtp_config.content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE;
1729
1730 smtp_config.sbcfg.buf_size = FILEDATA_CONTENT_INSPECT_WINDOW;
1731}
1732
576ec7da
AS
1733/*
1734 * \test Test STARTTLS.
1735 */
e43ce0a9 1736static int SMTPParserTest01(void)
576ec7da
AS
1737{
1738 int result = 0;
1739 Flow f;
1740 int r = 0;
1741
1742 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1743 uint8_t welcome_reply[] = {
1744 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1745 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1746 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1747 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1748 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1749 0x0d, 0x0a
1750 };
1751 uint32_t welcome_reply_len = sizeof(welcome_reply);
1752
1753 /* EHLO [192.168.0.158]<CR><LF> */
1754 uint8_t request1[] = {
1755 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
1756 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
1757 0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
1758 };
1759 uint32_t request1_len = sizeof(request1);
1760 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1761 * 250-SIZE 35882577<CR><LF>
1762 * 250-8BITMIME<CR><LF>
1763 * 250-STARTTLS<CR><LF>
1764 * 250 ENHANCEDSTATUSCODES<CR><LF>
1765 */
1766 uint8_t reply1[] = {
1767 0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
1768 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1769 0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
1770 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
1771 0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
1772 0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
1773 0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
1774 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
1775 0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
1776 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
1777 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
1778 0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
1779 0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
1780 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
1781 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
1782 0x44, 0x45, 0x53, 0x0d, 0x0a
1783 };
1784 uint32_t reply1_len = sizeof(reply1);
1785
1786 /* STARTTLS<CR><LF> */
1787 uint8_t request2[] = {
1788 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
1789 0x0d, 0x0a
1790 };
1791 uint32_t request2_len = sizeof(request2);
1792 /* 220 2.0.0 Ready to start TLS<CR><LF> */
1793 uint8_t reply2[] = {
1794 0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1795 0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
1796 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
1797 0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
1798 };
1799 uint32_t reply2_len = sizeof(reply2);
1800
1801 TcpSession ssn;
8dbf7a0d 1802 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
1803
1804 memset(&f, 0, sizeof(f));
1805 memset(&ssn, 0, sizeof(ssn));
1806
1807 FLOW_INITIALIZE(&f);
1808 f.protoctx = (void *)&ssn;
429c6388 1809 f.proto = IPPROTO_TCP;
576ec7da
AS
1810
1811 StreamTcpInitConfig(TRUE);
e43ce0a9 1812 SMTPTestInitConfig();
576ec7da 1813
cd3e32ce 1814 SCMutexLock(&f.m);
429c6388
AS
1815 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
1816 welcome_reply, welcome_reply_len);
576ec7da
AS
1817 if (r != 0) {
1818 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1819 SCMutexUnlock(&f.m);
576ec7da
AS
1820 goto end;
1821 }
cd3e32ce 1822 SCMutexUnlock(&f.m);
06904c90 1823 SMTPState *smtp_state = f.alstate;
576ec7da
AS
1824 if (smtp_state == NULL) {
1825 printf("no smtp state: ");
1826 goto end;
1827 }
1828 if (smtp_state->input_len != 0 ||
0d7159b5 1829 smtp_state->cmds_cnt != 0 ||
576ec7da 1830 smtp_state->cmds_idx != 0 ||
0d7159b5 1831 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
1832 printf("smtp parser in inconsistent state\n");
1833 goto end;
1834 }
1835
cd3e32ce 1836 SCMutexLock(&f.m);
429c6388
AS
1837 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
1838 request1, request1_len);
576ec7da
AS
1839 if (r != 0) {
1840 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1841 SCMutexUnlock(&f.m);
576ec7da
AS
1842 goto end;
1843 }
cd3e32ce 1844 SCMutexUnlock(&f.m);
576ec7da 1845 if (smtp_state->input_len != 0 ||
576ec7da
AS
1846 smtp_state->cmds_cnt != 1 ||
1847 smtp_state->cmds_idx != 0 ||
1848 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1849 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1850 printf("smtp parser in inconsistent state\n");
1851 goto end;
1852 }
1853
cd3e32ce 1854 SCMutexLock(&f.m);
429c6388
AS
1855 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
1856 reply1, reply1_len);
576ec7da
AS
1857 if (r != 0) {
1858 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1859 SCMutexUnlock(&f.m);
576ec7da
AS
1860 goto end;
1861 }
cd3e32ce 1862 SCMutexUnlock(&f.m);
576ec7da 1863 if (smtp_state->input_len != 0 ||
576ec7da
AS
1864 smtp_state->cmds_cnt != 0 ||
1865 smtp_state->cmds_idx != 0 ||
1866 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1867 printf("smtp parser in inconsistent state\n");
1868 goto end;
1869 }
1870
cd3e32ce 1871 SCMutexLock(&f.m);
429c6388
AS
1872 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
1873 request2, request2_len);
576ec7da
AS
1874 if (r != 0) {
1875 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1876 SCMutexUnlock(&f.m);
576ec7da
AS
1877 goto end;
1878 }
cd3e32ce 1879 SCMutexUnlock(&f.m);
576ec7da 1880 if (smtp_state->input_len != 0 ||
576ec7da
AS
1881 smtp_state->cmds_cnt != 1 ||
1882 smtp_state->cmds_idx != 0 ||
1883 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
1884 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1885 printf("smtp parser in inconsistent state\n");
1886 goto end;
1887 }
1888
cd3e32ce 1889 SCMutexLock(&f.m);
429c6388
AS
1890 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
1891 reply2, reply2_len);
576ec7da
AS
1892 if (r != 0) {
1893 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1894 SCMutexUnlock(&f.m);
576ec7da
AS
1895 goto end;
1896 }
cd3e32ce 1897 SCMutexUnlock(&f.m);
576ec7da 1898 if (smtp_state->input_len != 0 ||
576ec7da
AS
1899 smtp_state->cmds_cnt != 0 ||
1900 smtp_state->cmds_idx != 0 ||
1901 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1902 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1903 printf("smtp parser in inconsistent state\n");
1904 goto end;
1905 }
1906
1907 if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
c1558f5a 1908 !(ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
576ec7da
AS
1909 !(((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
1910 !(((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
1911 goto end;
1912 }
1913
1914 result = 1;
1915end:
429c6388 1916 if (alp_tctx != NULL)
fdefb65b 1917 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
1918 StreamTcpFreeConfig(TRUE);
1919 FLOW_DESTROY(&f);
1920 return result;
1921}
1922
1923/**
1924 * \test Test multiple DATA commands(full mail transactions).
1925 */
e43ce0a9 1926static int SMTPParserTest02(void)
576ec7da
AS
1927{
1928 int result = 0;
1929 Flow f;
1930 int r = 0;
1931
1932 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1933 uint8_t welcome_reply[] = {
1934 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1935 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1936 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1937 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1938 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1939 0x0d, 0x0a
1940 };
1941 uint32_t welcome_reply_len = sizeof(welcome_reply);
1942
1943 /* EHLO boo.com<CR><LF> */
1944 uint8_t request1[] = {
1945 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
1946 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1947 };
1948 uint32_t request1_len = sizeof(request1);
1949 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1950 * 250-SIZE 35882577<CR><LF>
1951 * 250-8BITMIME<CR><LF>
1952 * 250-STARTTLS<CR><LF>
1953 * 250 ENHANCEDSTATUSCODES<CR><LF>
1954 */
1955 uint8_t reply1[] = {
1956 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
1957 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1958 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1959 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
1960 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
1961 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
1962 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
1963 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
1964 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
1965 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
1966 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
1967 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
1968 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
1969 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
1970 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
1971 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
1972 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
1973 };
1974 uint32_t reply1_len = sizeof(reply1);
1975
1976 /* MAIL FROM:asdff@asdf.com<CR><LF> */
1977 uint8_t request2[] = {
1978 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
1979 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
1980 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
1981 0x0d, 0x0a
1982 };
1983 uint32_t request2_len = sizeof(request2);
1984 /* 250 2.1.0 Ok<CR><LF> */
1985 uint8_t reply2[] = {
1986 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1987 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1988 };
1989 uint32_t reply2_len = sizeof(reply2);
1990
1991 /* RCPT TO:bimbs@gmail.com<CR><LF> */
1992 uint8_t request3[] = {
1993 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
1994 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
1995 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
1996 0x0a
1997 };
1998 uint32_t request3_len = sizeof(request3);
1999 /* 250 2.1.5 Ok<CR><LF> */
2000 uint8_t reply3[] = {
2001 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2002 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2003 };
2004 uint32_t reply3_len = sizeof(reply3);
2005
2006 /* DATA<CR><LF> */
2007 uint8_t request4[] = {
2008 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2009 };
2010 uint32_t request4_len = sizeof(request4);
2011 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2012 uint8_t reply4[] = {
2013 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2014 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2015 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2016 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2017 0x4c, 0x46, 0x3e, 0x0d, 0x0a
2018 };
2019 uint32_t reply4_len = sizeof(reply4);
2020
2021 /* FROM:asdff@asdf.com<CR><LF> */
2022 uint8_t request5_1[] = {
2023 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2024 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2025 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2026 };
2027 uint32_t request5_1_len = sizeof(request5_1);
2028 /* TO:bimbs@gmail.com<CR><LF> */
2029 uint8_t request5_2[] = {
2030 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2031 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2032 0x6f, 0x6d, 0x0d, 0x0a
2033 };
2034 uint32_t request5_2_len = sizeof(request5_2);
2035 /* <CR><LF> */
2036 uint8_t request5_3[] = {
2037 0x0d, 0x0a
2038 };
2039 uint32_t request5_3_len = sizeof(request5_3);
2040 /* this is test mail1<CR><LF> */
2041 uint8_t request5_4[] = {
2042 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2043 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2044 0x6c, 0x31, 0x0d, 0x0a
2045 };
2046 uint32_t request5_4_len = sizeof(request5_4);
2047 /* .<CR><LF> */
2048 uint8_t request5_5[] = {
2049 0x2e, 0x0d, 0x0a
2050 };
2051 uint32_t request5_5_len = sizeof(request5_5);
2052 /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
2053 uint8_t reply5[] = {
2054 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2055 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2056 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2057 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
2058 0x46, 0x32, 0x0d, 0x0a
2059 };
2060 uint32_t reply5_len = sizeof(reply5);
2061
2062 /* MAIL FROM:asdfg@asdf.com<CR><LF> */
2063 uint8_t request6[] = {
2064 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2065 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
2066 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2067 0x0d, 0x0a
2068 };
2069 uint32_t request6_len = sizeof(request6);
2070 /* 250 2.1.0 Ok<CR><LF> */
2071 uint8_t reply6[] = {
2072 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2073 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2074 };
2075 uint32_t reply6_len = sizeof(reply6);
2076
2077 /* RCPT TO:bimbs@gmail.com<CR><LF> */
2078 uint8_t request7[] = {
2079 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2080 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2081 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2082 0x0a
2083 };
2084 uint32_t request7_len = sizeof(request7);
2085 /* 250 2.1.5 Ok<CR><LF> */
2086 uint8_t reply7[] = {
2087 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2088 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2089 };
2090 uint32_t reply7_len = sizeof(reply7);
2091
2092 /* DATA<CR><LF> */
2093 uint8_t request8[] = {
2094 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2095 };
2096 uint32_t request8_len = sizeof(request8);
2097 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2098 uint8_t reply8[] = {
2099 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2100 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2101 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2102 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2103 0x4c, 0x46, 0x3e, 0x0d, 0x0a
2104 };
2105 uint32_t reply8_len = sizeof(reply8);
2106
2107 /* FROM:asdfg@gmail.com<CR><LF> */
2108 uint8_t request9_1[] = {
2109 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2110 0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
2111 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2112 };
2113 uint32_t request9_1_len = sizeof(request9_1);
2114 /* TO:bimbs@gmail.com<CR><LF> */
2115 uint8_t request9_2[] = {
2116 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2117 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2118 0x6f, 0x6d, 0x0d, 0x0a
2119 };
2120 uint32_t request9_2_len = sizeof(request9_2);
2121 /* <CR><LF> */
2122 uint8_t request9_3[] = {
2123 0x0d, 0x0a
2124 };
2125 uint32_t request9_3_len = sizeof(request9_3);
2126 /* this is test mail2<CR><LF> */
2127 uint8_t request9_4[] = {
2128 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2129 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2130 0x6c, 0x32, 0x0d, 0x0a
2131 };
2132 uint32_t request9_4_len = sizeof(request9_4);
2133 /* .<CR><LF> */
2134 uint8_t request9_5[] = {
2135 0x2e, 0x0d, 0x0a
2136 };
2137 uint32_t request9_5_len = sizeof(request9_5);
2138 /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
2139 uint8_t reply9[] = {
2140 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2141 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2142 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2143 0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
2144 0x46, 0x32, 0x0d, 0x0a
2145 };
2146 uint32_t reply9_len = sizeof(reply9);
2147
2148 /* QUIT<CR><LF> */
2149 uint8_t request10[] = {
2150 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2151 };
2152 uint32_t request10_len = sizeof(request10);
2153 /* 221 2.0.0 Bye<CR><LF> */
2154 uint8_t reply10[] = {
2155 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2156 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2157 };
2158 uint32_t reply10_len = sizeof(reply10);
2159
2160 TcpSession ssn;
8dbf7a0d 2161 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
2162
2163 memset(&f, 0, sizeof(f));
2164 memset(&ssn, 0, sizeof(ssn));
2165
2166 FLOW_INITIALIZE(&f);
2167 f.protoctx = (void *)&ssn;
429c6388 2168 f.proto = IPPROTO_TCP;
576ec7da
AS
2169
2170 StreamTcpInitConfig(TRUE);
e43ce0a9 2171 SMTPTestInitConfig();
576ec7da 2172
cd3e32ce 2173 SCMutexLock(&f.m);
429c6388
AS
2174 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2175 welcome_reply, welcome_reply_len);
576ec7da
AS
2176 if (r != 0) {
2177 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2178 SCMutexUnlock(&f.m);
576ec7da
AS
2179 goto end;
2180 }
cd3e32ce 2181 SCMutexUnlock(&f.m);
06904c90 2182 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2183 if (smtp_state == NULL) {
2184 printf("no smtp state: ");
2185 goto end;
2186 }
2187 if (smtp_state->input_len != 0 ||
0d7159b5 2188 smtp_state->cmds_cnt != 0 ||
576ec7da 2189 smtp_state->cmds_idx != 0 ||
0d7159b5 2190 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
2191 printf("smtp parser in inconsistent state\n");
2192 goto end;
2193 }
2194
cd3e32ce 2195 SCMutexLock(&f.m);
429c6388
AS
2196 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2197 request1, request1_len);
576ec7da
AS
2198 if (r != 0) {
2199 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2200 SCMutexUnlock(&f.m);
576ec7da
AS
2201 goto end;
2202 }
cd3e32ce 2203 SCMutexUnlock(&f.m);
576ec7da 2204 if (smtp_state->input_len != 0 ||
576ec7da
AS
2205 smtp_state->cmds_cnt != 1 ||
2206 smtp_state->cmds_idx != 0 ||
2207 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2208 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2209 printf("smtp parser in inconsistent state\n");
2210 goto end;
2211 }
2212
cd3e32ce 2213 SCMutexLock(&f.m);
429c6388
AS
2214 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2215 reply1, reply1_len);
576ec7da
AS
2216 if (r != 0) {
2217 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2218 SCMutexUnlock(&f.m);
576ec7da
AS
2219 goto end;
2220 }
cd3e32ce 2221 SCMutexUnlock(&f.m);
576ec7da 2222 if (smtp_state->input_len != 0 ||
576ec7da
AS
2223 smtp_state->cmds_cnt != 0 ||
2224 smtp_state->cmds_idx != 0 ||
2225 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2226 printf("smtp parser in inconsistent state\n");
2227 goto end;
2228 }
2229
cd3e32ce 2230 SCMutexLock(&f.m);
429c6388
AS
2231 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2232 request2, request2_len);
576ec7da
AS
2233 if (r != 0) {
2234 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2235 SCMutexUnlock(&f.m);
576ec7da
AS
2236 goto end;
2237 }
cd3e32ce 2238 SCMutexUnlock(&f.m);
576ec7da 2239 if (smtp_state->input_len != 0 ||
576ec7da
AS
2240 smtp_state->cmds_cnt != 1 ||
2241 smtp_state->cmds_idx != 0 ||
2242 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2243 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2244 printf("smtp parser in inconsistent state\n");
2245 goto end;
2246 }
2247
cd3e32ce 2248 SCMutexLock(&f.m);
429c6388
AS
2249 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2250 reply2, reply2_len);
576ec7da
AS
2251 if (r != 0) {
2252 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2253 SCMutexUnlock(&f.m);
576ec7da
AS
2254 goto end;
2255 }
cd3e32ce 2256 SCMutexUnlock(&f.m);
576ec7da 2257 if (smtp_state->input_len != 0 ||
576ec7da
AS
2258 smtp_state->cmds_cnt != 0 ||
2259 smtp_state->cmds_idx != 0 ||
2260 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2261 printf("smtp parser in inconsistent state\n");
2262 goto end;
2263 }
2264
cd3e32ce 2265 SCMutexLock(&f.m);
429c6388
AS
2266 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2267 request3, request3_len);
576ec7da
AS
2268 if (r != 0) {
2269 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2270 SCMutexUnlock(&f.m);
576ec7da
AS
2271 goto end;
2272 }
cd3e32ce 2273 SCMutexUnlock(&f.m);
576ec7da 2274 if (smtp_state->input_len != 0 ||
576ec7da
AS
2275 smtp_state->cmds_cnt != 1 ||
2276 smtp_state->cmds_idx != 0 ||
2277 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2278 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2279 printf("smtp parser in inconsistent state\n");
2280 goto end;
2281 }
2282
cd3e32ce 2283 SCMutexLock(&f.m);
429c6388
AS
2284 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2285 reply3, reply3_len);
576ec7da
AS
2286 if (r != 0) {
2287 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2288 SCMutexUnlock(&f.m);
576ec7da
AS
2289 goto end;
2290 }
cd3e32ce 2291 SCMutexUnlock(&f.m);
576ec7da 2292 if (smtp_state->input_len != 0 ||
576ec7da
AS
2293 smtp_state->cmds_cnt != 0 ||
2294 smtp_state->cmds_idx != 0 ||
2295 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2296 printf("smtp parser in inconsistent state\n");
2297 goto end;
2298 }
2299
cd3e32ce 2300 SCMutexLock(&f.m);
429c6388
AS
2301 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2302 request4, request4_len);
576ec7da
AS
2303 if (r != 0) {
2304 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2305 SCMutexUnlock(&f.m);
576ec7da
AS
2306 goto end;
2307 }
cd3e32ce 2308 SCMutexUnlock(&f.m);
576ec7da 2309 if (smtp_state->input_len != 0 ||
576ec7da
AS
2310 smtp_state->cmds_cnt != 1 ||
2311 smtp_state->cmds_idx != 0 ||
2312 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2313 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2314 printf("smtp parser in inconsistent state\n");
2315 goto end;
2316 }
2317
cd3e32ce 2318 SCMutexLock(&f.m);
429c6388
AS
2319 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2320 reply4, reply4_len);
576ec7da
AS
2321 if (r != 0) {
2322 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2323 SCMutexUnlock(&f.m);
576ec7da
AS
2324 goto end;
2325 }
cd3e32ce 2326 SCMutexUnlock(&f.m);
576ec7da 2327 if (smtp_state->input_len != 0 ||
576ec7da
AS
2328 smtp_state->cmds_cnt != 0 ||
2329 smtp_state->cmds_idx != 0 ||
2330 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2331 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2332 printf("smtp parser in inconsistent state\n");
2333 goto end;
2334 }
2335
cd3e32ce 2336 SCMutexLock(&f.m);
429c6388
AS
2337 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2338 request5_1, request5_1_len);
576ec7da
AS
2339 if (r != 0) {
2340 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2341 SCMutexUnlock(&f.m);
576ec7da
AS
2342 goto end;
2343 }
cd3e32ce 2344 SCMutexUnlock(&f.m);
576ec7da 2345 if (smtp_state->input_len != 0 ||
576ec7da
AS
2346 smtp_state->cmds_cnt != 0 ||
2347 smtp_state->cmds_idx != 0 ||
2348 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2349 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2350
2351 printf("smtp parser in inconsistent state\n");
2352 goto end;
2353 }
2354
cd3e32ce 2355 SCMutexLock(&f.m);
429c6388
AS
2356 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2357 request5_2, request5_2_len);
576ec7da
AS
2358 if (r != 0) {
2359 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2360 SCMutexUnlock(&f.m);
576ec7da
AS
2361 goto end;
2362 }
cd3e32ce 2363 SCMutexUnlock(&f.m);
576ec7da 2364 if (smtp_state->input_len != 0 ||
576ec7da
AS
2365 smtp_state->cmds_cnt != 0 ||
2366 smtp_state->cmds_idx != 0 ||
2367 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2368 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2369
2370 printf("smtp parser in inconsistent state\n");
2371 goto end;
2372 }
2373
cd3e32ce 2374 SCMutexLock(&f.m);
429c6388
AS
2375 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2376 request5_3, request5_3_len);
576ec7da
AS
2377 if (r != 0) {
2378 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2379 SCMutexUnlock(&f.m);
576ec7da
AS
2380 goto end;
2381 }
cd3e32ce 2382 SCMutexUnlock(&f.m);
576ec7da 2383 if (smtp_state->input_len != 0 ||
576ec7da
AS
2384 smtp_state->cmds_cnt != 0 ||
2385 smtp_state->cmds_idx != 0 ||
2386 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2387 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2388
2389 printf("smtp parser in inconsistent state\n");
2390 goto end;
2391 }
2392
cd3e32ce 2393 SCMutexLock(&f.m);
429c6388
AS
2394 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2395 request5_4, request5_4_len);
576ec7da
AS
2396 if (r != 0) {
2397 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2398 SCMutexUnlock(&f.m);
576ec7da
AS
2399 goto end;
2400 }
cd3e32ce 2401 SCMutexUnlock(&f.m);
576ec7da 2402 if (smtp_state->input_len != 0 ||
576ec7da
AS
2403 smtp_state->cmds_cnt != 0 ||
2404 smtp_state->cmds_idx != 0 ||
2405 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2406 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2407
2408 printf("smtp parser in inconsistent state\n");
2409 goto end;
2410 }
2411
cd3e32ce 2412 SCMutexLock(&f.m);
429c6388
AS
2413 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2414 request5_5, request5_5_len);
576ec7da
AS
2415 if (r != 0) {
2416 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2417 SCMutexUnlock(&f.m);
576ec7da
AS
2418 goto end;
2419 }
cd3e32ce 2420 SCMutexUnlock(&f.m);
576ec7da 2421 if (smtp_state->input_len != 0 ||
576ec7da
AS
2422 smtp_state->cmds_cnt != 1 ||
2423 smtp_state->cmds_idx != 0 ||
2424 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2425 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2426 printf("smtp parser in inconsistent state\n");
2427 goto end;
2428 }
2429
cd3e32ce 2430 SCMutexLock(&f.m);
429c6388
AS
2431 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2432 reply5, reply5_len);
576ec7da
AS
2433 if (r != 0) {
2434 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2435 SCMutexUnlock(&f.m);
576ec7da
AS
2436 goto end;
2437 }
cd3e32ce 2438 SCMutexUnlock(&f.m);
576ec7da 2439 if (smtp_state->input_len != 0 ||
576ec7da
AS
2440 smtp_state->cmds_cnt != 0 ||
2441 smtp_state->cmds_idx != 0 ||
2442 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2443 printf("smtp parser in inconsistent state\n");
2444 goto end;
2445 }
2446
cd3e32ce 2447 SCMutexLock(&f.m);
429c6388
AS
2448 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2449 request6, request6_len);
576ec7da
AS
2450 if (r != 0) {
2451 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2452 SCMutexUnlock(&f.m);
576ec7da
AS
2453 goto end;
2454 }
cd3e32ce 2455 SCMutexUnlock(&f.m);
576ec7da 2456 if (smtp_state->input_len != 0 ||
576ec7da
AS
2457 smtp_state->cmds_cnt != 1 ||
2458 smtp_state->cmds_idx != 0 ||
2459 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2460 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2461 printf("smtp parser in inconsistent state\n");
2462 goto end;
2463 }
2464
cd3e32ce 2465 SCMutexLock(&f.m);
429c6388
AS
2466 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2467 reply6, reply6_len);
576ec7da
AS
2468 if (r != 0) {
2469 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2470 SCMutexUnlock(&f.m);
576ec7da
AS
2471 goto end;
2472 }
cd3e32ce 2473 SCMutexUnlock(&f.m);
576ec7da 2474 if (smtp_state->input_len != 0 ||
576ec7da
AS
2475 smtp_state->cmds_cnt != 0 ||
2476 smtp_state->cmds_idx != 0 ||
2477 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2478 printf("smtp parser in inconsistent state\n");
2479 goto end;
2480 }
2481
cd3e32ce 2482 SCMutexLock(&f.m);
429c6388
AS
2483 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2484 request7, request7_len);
576ec7da
AS
2485 if (r != 0) {
2486 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2487 SCMutexUnlock(&f.m);
576ec7da
AS
2488 goto end;
2489 }
cd3e32ce 2490 SCMutexUnlock(&f.m);
576ec7da 2491 if (smtp_state->input_len != 0 ||
576ec7da
AS
2492 smtp_state->cmds_cnt != 1 ||
2493 smtp_state->cmds_idx != 0 ||
2494 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2495 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2496 printf("smtp parser in inconsistent state\n");
2497 goto end;
2498 }
2499
cd3e32ce 2500 SCMutexLock(&f.m);
429c6388
AS
2501 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2502 reply7, reply7_len);
576ec7da
AS
2503 if (r != 0) {
2504 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2505 SCMutexUnlock(&f.m);
576ec7da
AS
2506 goto end;
2507 }
cd3e32ce 2508 SCMutexUnlock(&f.m);
576ec7da 2509 if (smtp_state->input_len != 0 ||
576ec7da
AS
2510 smtp_state->cmds_cnt != 0 ||
2511 smtp_state->cmds_idx != 0 ||
2512 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2513 printf("smtp parser in inconsistent state\n");
2514 goto end;
2515 }
2516
cd3e32ce 2517 SCMutexLock(&f.m);
429c6388
AS
2518 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2519 request8, request8_len);
576ec7da
AS
2520 if (r != 0) {
2521 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2522 SCMutexUnlock(&f.m);
576ec7da
AS
2523 goto end;
2524 }
cd3e32ce 2525 SCMutexUnlock(&f.m);
576ec7da 2526 if (smtp_state->input_len != 0 ||
576ec7da
AS
2527 smtp_state->cmds_cnt != 1 ||
2528 smtp_state->cmds_idx != 0 ||
2529 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2530 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2531 printf("smtp parser in inconsistent state\n");
2532 goto end;
2533 }
2534
cd3e32ce 2535 SCMutexLock(&f.m);
429c6388
AS
2536 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2537 reply8, reply8_len);
576ec7da
AS
2538 if (r != 0) {
2539 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2540 SCMutexUnlock(&f.m);
576ec7da
AS
2541 goto end;
2542 }
cd3e32ce 2543 SCMutexUnlock(&f.m);
576ec7da 2544 if (smtp_state->input_len != 0 ||
576ec7da
AS
2545 smtp_state->cmds_cnt != 0 ||
2546 smtp_state->cmds_idx != 0 ||
2547 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2548 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2549 printf("smtp parser in inconsistent state\n");
2550 goto end;
2551 }
2552
cd3e32ce 2553 SCMutexLock(&f.m);
429c6388
AS
2554 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2555 request9_1, request9_1_len);
576ec7da
AS
2556 if (r != 0) {
2557 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2558 SCMutexUnlock(&f.m);
576ec7da
AS
2559 goto end;
2560 }
cd3e32ce 2561 SCMutexUnlock(&f.m);
576ec7da 2562 if (smtp_state->input_len != 0 ||
576ec7da
AS
2563 smtp_state->cmds_cnt != 0 ||
2564 smtp_state->cmds_idx != 0 ||
2565 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2566 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2567
2568 printf("smtp parser in inconsistent state\n");
2569 goto end;
2570 }
2571
cd3e32ce 2572 SCMutexLock(&f.m);
429c6388
AS
2573 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2574 request9_2, request9_2_len);
576ec7da
AS
2575 if (r != 0) {
2576 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2577 SCMutexUnlock(&f.m);
576ec7da
AS
2578 goto end;
2579 }
cd3e32ce 2580 SCMutexUnlock(&f.m);
576ec7da 2581 if (smtp_state->input_len != 0 ||
576ec7da
AS
2582 smtp_state->cmds_cnt != 0 ||
2583 smtp_state->cmds_idx != 0 ||
2584 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2585 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2586
2587 printf("smtp parser in inconsistent state\n");
2588 goto end;
2589 }
2590
cd3e32ce 2591 SCMutexLock(&f.m);
429c6388
AS
2592 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2593 request9_3, request9_3_len);
576ec7da
AS
2594 if (r != 0) {
2595 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2596 SCMutexUnlock(&f.m);
576ec7da
AS
2597 goto end;
2598 }
cd3e32ce 2599 SCMutexUnlock(&f.m);
576ec7da 2600 if (smtp_state->input_len != 0 ||
576ec7da
AS
2601 smtp_state->cmds_cnt != 0 ||
2602 smtp_state->cmds_idx != 0 ||
2603 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2604 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2605
2606 printf("smtp parser in inconsistent state\n");
2607 goto end;
2608 }
2609
cd3e32ce 2610 SCMutexLock(&f.m);
429c6388
AS
2611 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2612 request9_4, request9_4_len);
576ec7da
AS
2613 if (r != 0) {
2614 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2615 SCMutexUnlock(&f.m);
576ec7da
AS
2616 goto end;
2617 }
cd3e32ce 2618 SCMutexUnlock(&f.m);
576ec7da 2619 if (smtp_state->input_len != 0 ||
576ec7da
AS
2620 smtp_state->cmds_cnt != 0 ||
2621 smtp_state->cmds_idx != 0 ||
2622 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2623 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2624
2625 printf("smtp parser in inconsistent state\n");
2626 goto end;
2627 }
2628
cd3e32ce 2629 SCMutexLock(&f.m);
429c6388
AS
2630 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2631 request9_5, request9_5_len);
576ec7da
AS
2632 if (r != 0) {
2633 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2634 SCMutexUnlock(&f.m);
576ec7da
AS
2635 goto end;
2636 }
cd3e32ce 2637 SCMutexUnlock(&f.m);
576ec7da 2638 if (smtp_state->input_len != 0 ||
576ec7da
AS
2639 smtp_state->cmds_cnt != 1 ||
2640 smtp_state->cmds_idx != 0 ||
2641 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2642 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2643 printf("smtp parser in inconsistent state\n");
2644 goto end;
2645 }
2646
cd3e32ce 2647 SCMutexLock(&f.m);
429c6388
AS
2648 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2649 reply9, reply9_len);
576ec7da
AS
2650 if (r != 0) {
2651 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2652 SCMutexUnlock(&f.m);
576ec7da
AS
2653 goto end;
2654 }
cd3e32ce 2655 SCMutexUnlock(&f.m);
576ec7da 2656 if (smtp_state->input_len != 0 ||
576ec7da
AS
2657 smtp_state->cmds_cnt != 0 ||
2658 smtp_state->cmds_idx != 0 ||
2659 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2660 printf("smtp parser in inconsistent state\n");
2661 goto end;
2662 }
2663
cd3e32ce 2664 SCMutexLock(&f.m);
429c6388
AS
2665 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2666 request10, request10_len);
576ec7da
AS
2667 if (r != 0) {
2668 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2669 SCMutexUnlock(&f.m);
576ec7da
AS
2670 goto end;
2671 }
cd3e32ce 2672 SCMutexUnlock(&f.m);
576ec7da 2673 if (smtp_state->input_len != 0 ||
576ec7da
AS
2674 smtp_state->cmds_cnt != 1 ||
2675 smtp_state->cmds_idx != 0 ||
2676 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2677 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2678 printf("smtp parser in inconsistent state\n");
2679 goto end;
2680 }
2681
cd3e32ce 2682 SCMutexLock(&f.m);
429c6388
AS
2683 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2684 reply10, reply10_len);
576ec7da
AS
2685 if (r != 0) {
2686 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2687 SCMutexUnlock(&f.m);
576ec7da
AS
2688 goto end;
2689 }
cd3e32ce 2690 SCMutexUnlock(&f.m);
576ec7da 2691 if (smtp_state->input_len != 0 ||
576ec7da
AS
2692 smtp_state->cmds_cnt != 0 ||
2693 smtp_state->cmds_idx != 0 ||
2694 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2695 printf("smtp parser in inconsistent state\n");
2696 goto end;
2697 }
2698
2699 result = 1;
2700end:
429c6388 2701 if (alp_tctx != NULL)
fdefb65b 2702 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
2703 StreamTcpFreeConfig(TRUE);
2704 FLOW_DESTROY(&f);
2705 return result;
2706}
2707
2708/**
2709 * \test Testing parsing pipelined commands.
2710 */
e43ce0a9 2711static int SMTPParserTest03(void)
576ec7da
AS
2712{
2713 int result = 0;
2714 Flow f;
2715 int r = 0;
2716
2717 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2718 uint8_t welcome_reply[] = {
2719 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2720 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2721 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2722 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2723 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2724 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2725 };
2726 uint32_t welcome_reply_len = sizeof(welcome_reply);
2727
2728 /* EHLO boo.com<CR><LF> */
2729 uint8_t request1[] = {
2730 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2731 0x2e, 0x63, 0x6f, 0x6d, 0x0a
2732 };
2733 uint32_t request1_len = sizeof(request1);
2734 /* 250-poona_slack_vm1.localdomain<CR><LF>
2735 * 250-PIPELINING<CR><LF>
2736 * 250-SIZE 10240000<CR><LF>
2737 * 250-VRFY<CR><LF>
2738 * 250-ETRN<CR><LF>
2739 * 250-ENHANCEDSTATUSCODES<CR><LF>
2740 * 250-8BITMIME<CR><LF>
2741 * 250 DSN<CR><LF>
2742 */
2743 uint8_t reply1[] = {
2744 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2745 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2746 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2747 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2748 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
2749 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
2750 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2751 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2752 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2753 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2754 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2755 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2756 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2757 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2758 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2759 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2760 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2761 };
2762 uint32_t reply1_len = sizeof(reply1);
2763
2764 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
2765 * RCPT TO:pbsf@asdfs.com<CR><LF>
2766 * DATA<CR><LF>
2767 */
2768 uint8_t request2[] = {
2769 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2770 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2771 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2772 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
2773 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2774 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2775 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2776 };
2777 uint32_t request2_len = sizeof(request2);
2778 /* 250 2.1.0 Ok<CR><LF>
2779 * 250 2.1.5 Ok<CR><LF>
2780 * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
2781 */
2782 uint8_t reply2[] = {
2783 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2784 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
2785 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
2786 0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
2787 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
2788 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
2789 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
2790 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
2791 0x0a
2792 };
2793 uint32_t reply2_len = sizeof(reply2);
2794
2795 TcpSession ssn;
8dbf7a0d 2796 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
2797
2798 memset(&f, 0, sizeof(f));
2799 memset(&ssn, 0, sizeof(ssn));
2800
2801 FLOW_INITIALIZE(&f);
2802 f.protoctx = (void *)&ssn;
429c6388 2803 f.proto = IPPROTO_TCP;
576ec7da
AS
2804
2805 StreamTcpInitConfig(TRUE);
e43ce0a9 2806 SMTPTestInitConfig();
576ec7da 2807
cd3e32ce 2808 SCMutexLock(&f.m);
429c6388
AS
2809 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2810 welcome_reply, welcome_reply_len);
576ec7da
AS
2811 if (r != 0) {
2812 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2813 SCMutexUnlock(&f.m);
576ec7da
AS
2814 goto end;
2815 }
cd3e32ce 2816 SCMutexUnlock(&f.m);
06904c90 2817 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2818 if (smtp_state == NULL) {
2819 printf("no smtp state: ");
2820 goto end;
2821 }
2822 if (smtp_state->input_len != 0 ||
0d7159b5 2823 smtp_state->cmds_cnt != 0 ||
576ec7da 2824 smtp_state->cmds_idx != 0 ||
0d7159b5 2825 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
2826 printf("smtp parser in inconsistent state\n");
2827 goto end;
2828 }
2829
cd3e32ce 2830 SCMutexLock(&f.m);
429c6388
AS
2831 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2832 request1, request1_len);
576ec7da
AS
2833 if (r != 0) {
2834 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2835 SCMutexUnlock(&f.m);
576ec7da
AS
2836 goto end;
2837 }
cd3e32ce 2838 SCMutexUnlock(&f.m);
576ec7da 2839 if (smtp_state->input_len != 0 ||
576ec7da
AS
2840 smtp_state->cmds_cnt != 1 ||
2841 smtp_state->cmds_idx != 0 ||
2842 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2843 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2844 printf("smtp parser in inconsistent state\n");
2845 goto end;
2846 }
2847
cd3e32ce 2848 SCMutexLock(&f.m);
429c6388
AS
2849 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2850 reply1, reply1_len);
576ec7da
AS
2851 if (r != 0) {
2852 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2853 SCMutexUnlock(&f.m);
576ec7da
AS
2854 goto end;
2855 }
cd3e32ce 2856 SCMutexUnlock(&f.m);
576ec7da 2857 if (smtp_state->input_len != 0 ||
576ec7da
AS
2858 smtp_state->cmds_cnt != 0 ||
2859 smtp_state->cmds_idx != 0 ||
2860 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2861 printf("smtp parser in inconsistent state\n");
2862 goto end;
2863 }
2864
cd3e32ce 2865 SCMutexLock(&f.m);
429c6388
AS
2866 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2867 request2, request2_len);
576ec7da
AS
2868 if (r != 0) {
2869 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2870 SCMutexUnlock(&f.m);
576ec7da
AS
2871 goto end;
2872 }
cd3e32ce 2873 SCMutexUnlock(&f.m);
576ec7da 2874 if (smtp_state->input_len != 0 ||
576ec7da
AS
2875 smtp_state->cmds_cnt != 3 ||
2876 smtp_state->cmds_idx != 0 ||
2877 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2878 smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
2879 smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
2880 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2881 printf("smtp parser in inconsistent state\n");
2882 goto end;
2883 }
2884
cd3e32ce 2885 SCMutexLock(&f.m);
429c6388
AS
2886 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2887 reply2, reply2_len);
576ec7da
AS
2888 if (r != 0) {
2889 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2890 SCMutexUnlock(&f.m);
576ec7da
AS
2891 goto end;
2892 }
cd3e32ce 2893 SCMutexUnlock(&f.m);
576ec7da 2894 if (smtp_state->input_len != 0 ||
576ec7da
AS
2895 smtp_state->cmds_cnt != 0 ||
2896 smtp_state->cmds_idx != 0 ||
2897 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2898 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2899 printf("smtp parser in inconsistent state\n");
2900 goto end;
2901 }
2902
2903 result = 1;
2904end:
429c6388 2905 if (alp_tctx != NULL)
fdefb65b 2906 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
2907 StreamTcpFreeConfig(TRUE);
2908 FLOW_DESTROY(&f);
2909 return result;
2910}
2911
2912/*
2913 * \test Test smtp with just <LF> delimter instead of <CR><LF>.
2914 */
e43ce0a9 2915static int SMTPParserTest04(void)
576ec7da
AS
2916{
2917 int result = 0;
2918 Flow f;
2919 int r = 0;
2920
2921 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2922 uint8_t welcome_reply[] = {
2923 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2924 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2925 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2926 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2927 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2928 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2929 };
2930 uint32_t welcome_reply_len = sizeof(welcome_reply);
2931
2932 /* EHLO boo.com<CR><LF> */
2933 uint8_t request1[] = {
2934 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2935 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2936 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2937 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2938 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2939 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2940 };
2941 uint32_t request1_len = sizeof(request1);
2942
2943 TcpSession ssn;
8dbf7a0d 2944 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
2945
2946 memset(&f, 0, sizeof(f));
2947 memset(&ssn, 0, sizeof(ssn));
2948
2949 FLOW_INITIALIZE(&f);
2950 f.protoctx = (void *)&ssn;
429c6388 2951 f.proto = IPPROTO_TCP;
576ec7da
AS
2952
2953 StreamTcpInitConfig(TRUE);
e43ce0a9 2954 SMTPTestInitConfig();
576ec7da 2955
cd3e32ce 2956 SCMutexLock(&f.m);
429c6388
AS
2957 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2958 welcome_reply, welcome_reply_len);
576ec7da
AS
2959 if (r != 0) {
2960 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2961 SCMutexUnlock(&f.m);
576ec7da
AS
2962 goto end;
2963 }
cd3e32ce 2964 SCMutexUnlock(&f.m);
06904c90 2965 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2966 if (smtp_state == NULL) {
2967 printf("no smtp state: ");
2968 goto end;
2969 }
2970 if (smtp_state->input_len != 0 ||
0d7159b5 2971 smtp_state->cmds_cnt != 0 ||
576ec7da 2972 smtp_state->cmds_idx != 0 ||
0d7159b5 2973 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
2974 printf("smtp parser in inconsistent state\n");
2975 goto end;
2976 }
2977
cd3e32ce 2978 SCMutexLock(&f.m);
429c6388
AS
2979 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2980 request1, request1_len);
576ec7da
AS
2981 if (r != 0) {
2982 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2983 SCMutexUnlock(&f.m);
576ec7da
AS
2984 goto end;
2985 }
cd3e32ce 2986 SCMutexUnlock(&f.m);
576ec7da 2987 if (smtp_state->input_len != 0 ||
576ec7da
AS
2988 smtp_state->cmds_cnt != 1 ||
2989 smtp_state->cmds_idx != 0 ||
2990 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2991 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2992 printf("smtp parser in inconsistent state\n");
2993 goto end;
2994 }
2995
2996 result = 1;
2997end:
429c6388 2998 if (alp_tctx != NULL)
fdefb65b 2999 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
3000 StreamTcpFreeConfig(TRUE);
3001 FLOW_DESTROY(&f);
3002 return result;
3003}
3004
3005/*
3006 * \test Test STARTTLS fail.
3007 */
e43ce0a9 3008static int SMTPParserTest05(void)
576ec7da
AS
3009{
3010 int result = 0;
3011 Flow f;
3012 int r = 0;
3013
3014 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3015 uint8_t welcome_reply[] = {
3016 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3017 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3018 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3019 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3020 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3021 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3022 };
3023 uint32_t welcome_reply_len = sizeof(welcome_reply);
3024
3025 /* EHLO boo.com<CR><LF> */
3026 uint8_t request1[] = {
3027 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3028 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3029 };
3030 uint32_t request1_len = sizeof(request1);
3031 /* 250-poona_slack_vm1.localdomain<CR><LF>
3032 * 250-PIPELINING<CR><LF>
3033 * 250-SIZE 10240000<CR><LF>
3034 * 250-VRFY<CR><LF>
3035 * 250-ETRN<CR><LF>
3036 * 250-ENHANCEDSTATUSCODES<CR><LF>
3037 * 250-8BITMIME<CR><LF>
3038 * 250 DSN<CR><LF>
3039 */
3040 uint8_t reply1[] = {
3041 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3042 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3043 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3044 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3045 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3046 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3047 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3048 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3049 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3050 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3051 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3052 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3053 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3054 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3055 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3056 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3057 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3058 };
3059 uint32_t reply1_len = sizeof(reply1);
3060
3061 /* STARTTLS<CR><LF> */
3062 uint8_t request2[] = {
3063 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3064 0x0d, 0x0a
3065 };
3066 uint32_t request2_len = sizeof(request2);
3067 /* 502 5.5.2 Error: command not recognized<CR><LF> */
3068 uint8_t reply2[] = {
3069 0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
3070 0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
3071 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
3072 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
3073 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
3074 0x0a
3075 };
3076 uint32_t reply2_len = sizeof(reply2);
3077
3078 /* QUIT<CR><LF> */
3079 uint8_t request3[] = {
3080 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3081
3082 };
3083 uint32_t request3_len = sizeof(request3);
3084 /* 221 2.0.0 Bye<CR><LF> */
3085 uint8_t reply3[] = {
3086 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3087 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3088 };
3089 uint32_t reply3_len = sizeof(reply3);
3090
3091 TcpSession ssn;
8dbf7a0d 3092 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
3093
3094 memset(&f, 0, sizeof(f));
3095 memset(&ssn, 0, sizeof(ssn));
3096
3097 FLOW_INITIALIZE(&f);
3098 f.protoctx = (void *)&ssn;
429c6388 3099 f.proto = IPPROTO_TCP;
576ec7da
AS
3100
3101 StreamTcpInitConfig(TRUE);
e43ce0a9 3102 SMTPTestInitConfig();
576ec7da 3103
cd3e32ce 3104 SCMutexLock(&f.m);
429c6388
AS
3105 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3106 welcome_reply, welcome_reply_len);
576ec7da
AS
3107 if (r != 0) {
3108 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3109 SCMutexUnlock(&f.m);
576ec7da
AS
3110 goto end;
3111 }
cd3e32ce 3112 SCMutexUnlock(&f.m);
06904c90 3113 SMTPState *smtp_state = f.alstate;
576ec7da
AS
3114 if (smtp_state == NULL) {
3115 printf("no smtp state: ");
3116 goto end;
3117 }
3118 if (smtp_state->input_len != 0 ||
0d7159b5 3119 smtp_state->cmds_cnt != 0 ||
576ec7da 3120 smtp_state->cmds_idx != 0 ||
0d7159b5 3121 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
3122 printf("smtp parser in inconsistent state\n");
3123 goto end;
3124 }
3125
cd3e32ce 3126 SCMutexLock(&f.m);
429c6388
AS
3127 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3128 request1, request1_len);
576ec7da
AS
3129 if (r != 0) {
3130 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3131 SCMutexUnlock(&f.m);
576ec7da
AS
3132 goto end;
3133 }
cd3e32ce 3134 SCMutexUnlock(&f.m);
576ec7da 3135 if (smtp_state->input_len != 0 ||
576ec7da
AS
3136 smtp_state->cmds_cnt != 1 ||
3137 smtp_state->cmds_idx != 0 ||
3138 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3139 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3140 printf("smtp parser in inconsistent state\n");
3141 goto end;
3142 }
3143
cd3e32ce 3144 SCMutexLock(&f.m);
429c6388
AS
3145 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3146 reply1, reply1_len);
576ec7da
AS
3147 if (r != 0) {
3148 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3149 SCMutexUnlock(&f.m);
576ec7da
AS
3150 goto end;
3151 }
cd3e32ce 3152 SCMutexUnlock(&f.m);
576ec7da 3153 if (smtp_state->input_len != 0 ||
576ec7da
AS
3154 smtp_state->cmds_cnt != 0 ||
3155 smtp_state->cmds_idx != 0 ||
3156 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3157 printf("smtp parser in inconsistent state\n");
3158 goto end;
3159 }
3160
cd3e32ce 3161 SCMutexLock(&f.m);
429c6388
AS
3162 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3163 request2, request2_len);
576ec7da
AS
3164 if (r != 0) {
3165 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3166 SCMutexUnlock(&f.m);
576ec7da
AS
3167 goto end;
3168 }
cd3e32ce 3169 SCMutexUnlock(&f.m);
576ec7da 3170 if (smtp_state->input_len != 0 ||
576ec7da
AS
3171 smtp_state->cmds_cnt != 1 ||
3172 smtp_state->cmds_idx != 0 ||
3173 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
3174 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3175 printf("smtp parser in inconsistent state\n");
3176 goto end;
3177 }
3178
cd3e32ce 3179 SCMutexLock(&f.m);
429c6388
AS
3180 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3181 reply2, reply2_len);
576ec7da
AS
3182 if (r != 0) {
3183 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3184 SCMutexUnlock(&f.m);
576ec7da
AS
3185 goto end;
3186 }
cd3e32ce 3187 SCMutexUnlock(&f.m);
576ec7da 3188 if (smtp_state->input_len != 0 ||
576ec7da
AS
3189 smtp_state->cmds_cnt != 0 ||
3190 smtp_state->cmds_idx != 0 ||
3191 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
3192 printf("smtp parser in inconsistent state\n");
3193 goto end;
3194 }
3195
3196 if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
c1558f5a 3197 (ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
576ec7da
AS
3198 (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
3199 (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3200 goto end;
3201 }
3202
cd3e32ce 3203 SCMutexLock(&f.m);
429c6388
AS
3204 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3205 request3, request3_len);
576ec7da
AS
3206 if (r != 0) {
3207 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3208 SCMutexUnlock(&f.m);
576ec7da
AS
3209 goto end;
3210 }
cd3e32ce 3211 SCMutexUnlock(&f.m);
576ec7da 3212 if (smtp_state->input_len != 0 ||
576ec7da
AS
3213 smtp_state->cmds_cnt != 1 ||
3214 smtp_state->cmds_idx != 0 ||
3215 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3216 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3217 printf("smtp parser in inconsistent state\n");
3218 goto end;
3219 }
3220
cd3e32ce 3221 SCMutexLock(&f.m);
429c6388
AS
3222 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3223 reply3, reply3_len);
576ec7da
AS
3224 if (r != 0) {
3225 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3226 SCMutexUnlock(&f.m);
576ec7da
AS
3227 goto end;
3228 }
cd3e32ce 3229 SCMutexUnlock(&f.m);
576ec7da 3230 if (smtp_state->input_len != 0 ||
576ec7da
AS
3231 smtp_state->cmds_cnt != 0 ||
3232 smtp_state->cmds_idx != 0 ||
3233 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
3234 printf("smtp parser in inconsistent state\n");
3235 goto end;
3236 }
3237
3238 result = 1;
3239end:
429c6388 3240 if (alp_tctx != NULL)
fdefb65b 3241 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
3242 StreamTcpFreeConfig(TRUE);
3243 FLOW_DESTROY(&f);
3244 return result;
3245}
3246
d3ca65de
AS
3247/**
3248 * \test Test multiple DATA commands(full mail transactions).
3249 */
e43ce0a9 3250static int SMTPParserTest06(void)
d3ca65de
AS
3251{
3252 int result = 0;
3253 Flow f;
3254 int r = 0;
3255
3256 uint8_t welcome_reply[] = {
3257 0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
3258 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3259 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3260 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3261 0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
3262 0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
3263 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
3264 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
3265 0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
3266 0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
3267 0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
3268 0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
3269 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
3270 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
3271 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
3272 0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
3273 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
3274 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
3275 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
3276 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
3277 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
3278 0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
3279 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
3280 0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
3281 0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
3282 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
3283 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
3284 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
3285 0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
3286 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
3287 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
3288 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
3289 0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
3290 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
3291 0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
3292 0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
3293 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
3294 0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
3295 0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
3296 };
3297 uint32_t welcome_reply_len = sizeof(welcome_reply);
3298
3299 uint8_t request1[] = {
3300 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
3301 0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
3302 0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
3303 0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
3304 0x0a
3305 };
3306 uint32_t request1_len = sizeof(request1);
3307
3308 uint8_t reply1[] = {
3309 0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
3310 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3311 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3312 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3313 0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
3314 0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
3315 0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
3316 0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
3317 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
3318 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
3319 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
3320 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49,
3321 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35,
3322 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
3323 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3324 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
3325 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3326 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
3327 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3328 0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3329 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3330 0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3331 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
3332 0x0d, 0x0a
3333 };
3334 uint32_t reply1_len = sizeof(reply1);
3335
3336 /* MAIL FROM:asdff@asdf.com<CR><LF> */
3337 uint8_t request2[] = {
3338 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3339 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3340 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3341 0x0d, 0x0a
3342 };
3343 uint32_t request2_len = sizeof(request2);
3344 /* 250 2.1.0 Ok<CR><LF> */
3345 uint8_t reply2[] = {
3346 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3347 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3348 };
3349 uint32_t reply2_len = sizeof(reply2);
3350
3351 /* RCPT TO:bimbs@gmail.com<CR><LF> */
3352 uint8_t request3[] = {
3353 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3354 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3355 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3356 0x0a
3357 };
3358 uint32_t request3_len = sizeof(request3);
3359 /* 250 2.1.5 Ok<CR><LF> */
3360 uint8_t reply3[] = {
3361 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3362 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3363 };
3364 uint32_t reply3_len = sizeof(reply3);
3365
3366 /* BDAT 51<CR><LF> */
3367 uint8_t request4[] = {
3368 0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
3369 0x0a,
3370 };
3371 uint32_t request4_len = sizeof(request4);
3372
3373 uint8_t request5[] = {
3374 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3375 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3376 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3377 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
3378 };
3379 uint32_t request5_len = sizeof(request5);
3380
3381 uint8_t request6[] = {
3382 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3383 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3384 0x66, 0x0d, 0x0a,
3385 };
561630d8 3386 uint32_t request6_len = sizeof(request6);
d3ca65de
AS
3387
3388 TcpSession ssn;
8dbf7a0d 3389 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
d3ca65de
AS
3390
3391 memset(&f, 0, sizeof(f));
3392 memset(&ssn, 0, sizeof(ssn));
3393
3394 FLOW_INITIALIZE(&f);
3395 f.protoctx = (void *)&ssn;
429c6388 3396 f.proto = IPPROTO_TCP;
d3ca65de
AS
3397
3398 StreamTcpInitConfig(TRUE);
e43ce0a9 3399 SMTPTestInitConfig();
d3ca65de 3400
cd3e32ce 3401 SCMutexLock(&f.m);
429c6388
AS
3402 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3403 welcome_reply, welcome_reply_len);
d3ca65de
AS
3404 if (r != 0) {
3405 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3406 SCMutexUnlock(&f.m);
d3ca65de
AS
3407 goto end;
3408 }
cd3e32ce 3409 SCMutexUnlock(&f.m);
06904c90 3410 SMTPState *smtp_state = f.alstate;
d3ca65de
AS
3411 if (smtp_state == NULL) {
3412 printf("no smtp state: ");
3413 goto end;
3414 }
3415 if (smtp_state->input_len != 0 ||
0d7159b5 3416 smtp_state->cmds_cnt != 0 ||
d3ca65de 3417 smtp_state->cmds_idx != 0 ||
0d7159b5 3418 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
d3ca65de
AS
3419 printf("smtp parser in inconsistent state\n");
3420 goto end;
3421 }
3422
cd3e32ce 3423 SCMutexLock(&f.m);
429c6388
AS
3424 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3425 request1, request1_len);
d3ca65de
AS
3426 if (r != 0) {
3427 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3428 SCMutexUnlock(&f.m);
d3ca65de
AS
3429 goto end;
3430 }
cd3e32ce 3431 SCMutexUnlock(&f.m);
d3ca65de
AS
3432 if (smtp_state->input_len != 0 ||
3433 smtp_state->cmds_cnt != 1 ||
3434 smtp_state->cmds_idx != 0 ||
3435 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3436 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3437 printf("smtp parser in inconsistent state\n");
3438 goto end;
3439 }
3440
cd3e32ce 3441 SCMutexLock(&f.m);
429c6388
AS
3442 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3443 reply1, reply1_len);
d3ca65de
AS
3444 if (r != 0) {
3445 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3446 SCMutexUnlock(&f.m);
d3ca65de
AS
3447 goto end;
3448 }
cd3e32ce 3449 SCMutexUnlock(&f.m);
d3ca65de
AS
3450 if (smtp_state->input_len != 0 ||
3451 smtp_state->cmds_cnt != 0 ||
3452 smtp_state->cmds_idx != 0 ||
3453 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3454 printf("smtp parser in inconsistent state\n");
3455 goto end;
3456 }
3457
cd3e32ce 3458 SCMutexLock(&f.m);
429c6388
AS
3459 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3460 request2, request2_len);
d3ca65de
AS
3461 if (r != 0) {
3462 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3463 SCMutexUnlock(&f.m);
d3ca65de
AS
3464 goto end;
3465 }
cd3e32ce 3466 SCMutexUnlock(&f.m);
d3ca65de
AS
3467 if (smtp_state->input_len != 0 ||
3468 smtp_state->cmds_cnt != 1 ||
3469 smtp_state->cmds_idx != 0 ||
3470 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3471 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3472 printf("smtp parser in inconsistent state\n");
3473 goto end;
3474 }
3475
cd3e32ce 3476 SCMutexLock(&f.m);
429c6388
AS
3477 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3478 reply2, reply2_len);
d3ca65de
AS
3479 if (r != 0) {
3480 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3481 SCMutexUnlock(&f.m);
d3ca65de
AS
3482 goto end;
3483 }
cd3e32ce 3484 SCMutexUnlock(&f.m);
d3ca65de
AS
3485 if (smtp_state->input_len != 0 ||
3486 smtp_state->cmds_cnt != 0 ||
3487 smtp_state->cmds_idx != 0 ||
3488 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
3489 printf("smtp parser in inconsistent state\n");
3490 goto end;
3491 }
3492
cd3e32ce 3493 SCMutexLock(&f.m);
429c6388
AS
3494 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3495 request3, request3_len);
d3ca65de
AS
3496 if (r != 0) {
3497 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3498 SCMutexUnlock(&f.m);
d3ca65de
AS
3499 goto end;
3500 }
cd3e32ce 3501 SCMutexUnlock(&f.m);
d3ca65de
AS
3502 if (smtp_state->input_len != 0 ||
3503 smtp_state->cmds_cnt != 1 ||
3504 smtp_state->cmds_idx != 0 ||
3505 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3506 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3507 printf("smtp parser in inconsistent state\n");
3508 goto end;
3509 }
3510
cd3e32ce 3511 SCMutexLock(&f.m);
429c6388
AS
3512 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3513 reply3, reply3_len);
d3ca65de
AS
3514 if (r != 0) {
3515 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3516 SCMutexUnlock(&f.m);
d3ca65de
AS
3517 goto end;
3518 }
cd3e32ce 3519 SCMutexUnlock(&f.m);
d3ca65de
AS
3520 if (smtp_state->input_len != 0 ||
3521 smtp_state->cmds_cnt != 0 ||
3522 smtp_state->cmds_idx != 0 ||
3523 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
3524 printf("smtp parser in inconsistent state\n");
3525 goto end;
3526 }
3527
cd3e32ce 3528 SCMutexLock(&f.m);
429c6388
AS
3529 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3530 request4, request4_len);
d3ca65de
AS
3531 if (r != 0) {
3532 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3533 SCMutexUnlock(&f.m);
d3ca65de
AS
3534 goto end;
3535 }
cd3e32ce 3536 SCMutexUnlock(&f.m);
d3ca65de
AS
3537 if (smtp_state->input_len != 0 ||
3538 smtp_state->cmds_cnt != 1 ||
3539 smtp_state->cmds_idx != 0 ||
3540 smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
3541 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
3542 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
3543 smtp_state->bdat_chunk_len != 51 ||
3544 smtp_state->bdat_chunk_idx != 0) {
3545 printf("smtp parser in inconsistent state\n");
3546 goto end;
3547 }
3548
cd3e32ce 3549 SCMutexLock(&f.m);
429c6388
AS
3550 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3551 request5, request5_len);
d3ca65de
AS
3552 if (r != 0) {
3553 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3554 SCMutexUnlock(&f.m);
d3ca65de
AS
3555 goto end;
3556 }
cd3e32ce 3557 SCMutexUnlock(&f.m);
d3ca65de
AS
3558 if (smtp_state->input_len != 0 ||
3559 smtp_state->cmds_cnt != 1 ||
3560 smtp_state->cmds_idx != 0 ||
3561 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
3562 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
3563 smtp_state->bdat_chunk_len != 51 ||
3564 smtp_state->bdat_chunk_idx != 32) {
3565 printf("smtp parser in inconsistent state\n");
3566 goto end;
3567 }
3568
cd3e32ce 3569 SCMutexLock(&f.m);
429c6388
AS
3570 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3571 request6, request6_len);
d3ca65de
AS
3572 if (r != 0) {
3573 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3574 SCMutexUnlock(&f.m);
d3ca65de
AS
3575 goto end;
3576 }
cd3e32ce 3577 SCMutexUnlock(&f.m);
d3ca65de
AS
3578 if (smtp_state->input_len != 0 ||
3579 smtp_state->cmds_cnt != 1 ||
3580 smtp_state->cmds_idx != 0 ||
3581 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN ||
3582 smtp_state->bdat_chunk_len != 51 ||
3583 smtp_state->bdat_chunk_idx != 51) {
3584 printf("smtp parser in inconsistent state\n");
3585 goto end;
3586 }
3587
3588 result = 1;
3589end:
429c6388 3590 if (alp_tctx != NULL)
fdefb65b 3591 AppLayerParserThreadCtxFree(alp_tctx);
d3ca65de
AS
3592 StreamTcpFreeConfig(TRUE);
3593 FLOW_DESTROY(&f);
3594 return result;
3595}
3596
4a6908d3
AS
3597/*
3598 * \test Test retrieving lines when frag'ed.
3599 */
e43ce0a9 3600static int SMTPParserTest07(void)
4a6908d3
AS
3601{
3602 int result = 0;
3603 Flow f;
3604 int r = 0;
3605
3606 const char *request1_str = "EHLO boo.com";
3607 /* EHLO boo.com<CR> */
3608 uint8_t request1_1[] = {
3609 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3610 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3611 };
3612 int32_t request1_1_len = sizeof(request1_1);
3613
3614 /* <LF> */
3615 uint8_t request1_2[] = {
3616 0x0a
3617 };
3618 int32_t request1_2_len = sizeof(request1_2);
3619
3620 /* EHLO boo.com<CR><LF> */
3621 uint8_t request2[] = {
3622 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3623 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3624 };
3625 int32_t request2_len = sizeof(request2);
3626
3627 TcpSession ssn;
8dbf7a0d 3628 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3629
3630 memset(&f, 0, sizeof(f));
3631 memset(&ssn, 0, sizeof(ssn));
3632
3633 FLOW_INITIALIZE(&f);
3634 f.protoctx = (void *)&ssn;
429c6388 3635 f.proto = IPPROTO_TCP;
4a6908d3
AS
3636
3637 StreamTcpInitConfig(TRUE);
e43ce0a9 3638 SMTPTestInitConfig();
4a6908d3 3639
cd3e32ce 3640 SCMutexLock(&f.m);
429c6388
AS
3641 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3642 request1_1, request1_1_len);
4a6908d3
AS
3643 if (r != 0) {
3644 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3645 SCMutexUnlock(&f.m);
4a6908d3
AS
3646 goto end;
3647 }
cd3e32ce 3648 SCMutexUnlock(&f.m);
bf24272c 3649 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3650 if (smtp_state == NULL) {
3651 printf("no smtp state: ");
3652 goto end;
3653 }
3654 if (smtp_state->current_line != NULL ||
3655 smtp_state->current_line_len != 0 ||
3656 smtp_state->ts_current_line_db != 1 ||
3657 smtp_state->ts_db == NULL ||
3658 smtp_state->ts_db_len != request1_1_len ||
3659 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3660 printf("smtp parser in inconsistent state\n");
3661 goto end;
3662 }
3663
cd3e32ce 3664 SCMutexLock(&f.m);
429c6388
AS
3665 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3666 request1_2, request1_2_len);
4a6908d3
AS
3667 if (r != 0) {
3668 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3669 SCMutexUnlock(&f.m);
4a6908d3
AS
3670 goto end;
3671 }
cd3e32ce 3672 SCMutexUnlock(&f.m);
4a6908d3
AS
3673 if (smtp_state->ts_current_line_db != 1 ||
3674 smtp_state->ts_db == NULL ||
3675 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3676 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3677 smtp_state->current_line != smtp_state->ts_db ||
3678 smtp_state->current_line_len != smtp_state->ts_db_len) {
3679 printf("smtp parser in inconsistent state\n");
3680 goto end;
3681 }
3682
cd3e32ce 3683 SCMutexLock(&f.m);
429c6388
AS
3684 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3685 request2, request2_len);
4a6908d3
AS
3686 if (r != 0) {
3687 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3688 SCMutexUnlock(&f.m);
4a6908d3
AS
3689 goto end;
3690 }
cd3e32ce 3691 SCMutexUnlock(&f.m);
4a6908d3
AS
3692 if (smtp_state->ts_current_line_db != 0 ||
3693 smtp_state->ts_db != NULL ||
3694 smtp_state->ts_db_len != 0 ||
3695 smtp_state->current_line == NULL ||
3696 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3697 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3698 printf("smtp parser in inconsistent state\n");
3699 goto end;
3700 }
3701
3702 result = 1;
3703end:
429c6388 3704 if (alp_tctx != NULL)
fdefb65b 3705 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
3706 StreamTcpFreeConfig(TRUE);
3707 FLOW_DESTROY(&f);
3708 return result;
3709}
3710
3711/*
3712 * \test Test retrieving lines when frag'ed.
3713 */
e43ce0a9 3714static int SMTPParserTest08(void)
4a6908d3
AS
3715{
3716 int result = 0;
3717 Flow f;
3718 int r = 0;
3719
3720 const char *request1_str = "EHLO boo.com";
3721 /* EHLO boo.com */
3722 uint8_t request1_1[] = {
3723 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3724 0x2e, 0x63, 0x6f, 0x6d,
3725 };
3726 int32_t request1_1_len = sizeof(request1_1);
3727
3728 /* <CR><LF> */
3729 uint8_t request1_2[] = {
3730 0x0d, 0x0a
3731 };
3732 int32_t request1_2_len = sizeof(request1_2);
3733
3734 /* EHLO boo.com<CR><LF> */
3735 uint8_t request2[] = {
3736 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3737 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3738 };
3739 int32_t request2_len = sizeof(request2);
3740
3741 TcpSession ssn;
8dbf7a0d 3742 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3743
3744 memset(&f, 0, sizeof(f));
3745 memset(&ssn, 0, sizeof(ssn));
3746
3747 FLOW_INITIALIZE(&f);
3748 f.protoctx = (void *)&ssn;
429c6388 3749 f.proto = IPPROTO_TCP;
4a6908d3
AS
3750
3751 StreamTcpInitConfig(TRUE);
e43ce0a9 3752 SMTPTestInitConfig();
4a6908d3 3753
cd3e32ce 3754 SCMutexLock(&f.m);
429c6388
AS
3755 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3756 request1_1, request1_1_len);
4a6908d3
AS
3757 if (r != 0) {
3758 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3759 SCMutexUnlock(&f.m);
4a6908d3
AS
3760 goto end;
3761 }
cd3e32ce 3762 SCMutexUnlock(&f.m);
bf24272c 3763 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3764 if (smtp_state == NULL) {
3765 printf("no smtp state: ");
3766 goto end;
3767 }
3768 if (smtp_state->current_line != NULL ||
3769 smtp_state->current_line_len != 0 ||
3770 smtp_state->ts_current_line_db != 1 ||
3771 smtp_state->ts_db == NULL ||
3772 smtp_state->ts_db_len != request1_1_len ||
3773 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3774 printf("smtp parser in inconsistent state\n");
3775 goto end;
3776 }
3777
cd3e32ce 3778 SCMutexLock(&f.m);
429c6388
AS
3779 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3780 request1_2, request1_2_len);
4a6908d3
AS
3781 if (r != 0) {
3782 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3783 SCMutexUnlock(&f.m);
4a6908d3
AS
3784 goto end;
3785 }
cd3e32ce 3786 SCMutexUnlock(&f.m);
4a6908d3
AS
3787 if (smtp_state->ts_current_line_db != 1 ||
3788 smtp_state->ts_db == NULL ||
3789 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3790 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3791 smtp_state->current_line != smtp_state->ts_db ||
3792 smtp_state->current_line_len != smtp_state->ts_db_len) {
3793 printf("smtp parser in inconsistent state\n");
3794 goto end;
3795 }
3796
cd3e32ce 3797 SCMutexLock(&f.m);
429c6388
AS
3798 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3799 request2, request2_len);
4a6908d3
AS
3800 if (r != 0) {
3801 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3802 SCMutexUnlock(&f.m);
4a6908d3
AS
3803 goto end;
3804 }
cd3e32ce 3805 SCMutexUnlock(&f.m);
4a6908d3
AS
3806 if (smtp_state->ts_current_line_db != 0 ||
3807 smtp_state->ts_db != NULL ||
3808 smtp_state->ts_db_len != 0 ||
3809 smtp_state->current_line == NULL ||
3810 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3811 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3812 printf("smtp parser in inconsistent state\n");
3813 goto end;
3814 }
3815
3816 result = 1;
3817end:
429c6388 3818 if (alp_tctx != NULL)
fdefb65b 3819 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
3820 StreamTcpFreeConfig(TRUE);
3821 FLOW_DESTROY(&f);
3822 return result;
3823}
3824
3825/*
3826 * \test Test retrieving lines when frag'ed.
3827 */
e43ce0a9 3828static int SMTPParserTest09(void)
4a6908d3
AS
3829{
3830 int result = 0;
3831 Flow f;
3832 int r = 0;
3833
3834 const char *request1_str = "EHLO boo.com";
3835 /* EHLO boo. */
3836 uint8_t request1_1[] = {
3837 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3838 0x2e,
3839 };
3840 int32_t request1_1_len = sizeof(request1_1);
3841
3842 /* com<CR><LF> */
3843 uint8_t request1_2[] = {
3844 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3845 };
3846 int32_t request1_2_len = sizeof(request1_2);
3847
3848 /* EHLO boo.com<CR><LF> */
3849 uint8_t request2[] = {
3850 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3851 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3852 };
3853 int32_t request2_len = sizeof(request2);
3854
3855 TcpSession ssn;
8dbf7a0d 3856 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3857
3858 memset(&f, 0, sizeof(f));
3859 memset(&ssn, 0, sizeof(ssn));
3860
3861 FLOW_INITIALIZE(&f);
3862 f.protoctx = (void *)&ssn;
429c6388 3863 f.proto = IPPROTO_TCP;
4a6908d3
AS
3864
3865 StreamTcpInitConfig(TRUE);
e43ce0a9 3866 SMTPTestInitConfig();
4a6908d3 3867
cd3e32ce 3868 SCMutexLock(&f.m);
429c6388
AS
3869 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3870 request1_1, request1_1_len);
4a6908d3
AS
3871 if (r != 0) {
3872 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3873 SCMutexUnlock(&f.m);
4a6908d3
AS
3874 goto end;
3875 }
cd3e32ce 3876 SCMutexUnlock(&f.m);
bf24272c 3877 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3878 if (smtp_state == NULL) {
3879 printf("no smtp state: ");
3880 goto end;
3881 }
3882 if (smtp_state->current_line != NULL ||
3883 smtp_state->current_line_len != 0 ||
3884 smtp_state->ts_current_line_db != 1 ||
3885 smtp_state->ts_db == NULL ||
3886 smtp_state->ts_db_len != request1_1_len ||
3887 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3888 printf("smtp parser in inconsistent state\n");
3889 goto end;
3890 }
3891
cd3e32ce 3892 SCMutexLock(&f.m);
429c6388
AS
3893 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3894 request1_2, request1_2_len);
4a6908d3
AS
3895 if (r != 0) {
3896 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3897 SCMutexUnlock(&f.m);
4a6908d3
AS
3898 goto end;
3899 }
cd3e32ce 3900 SCMutexUnlock(&f.m);
4a6908d3
AS
3901 if (smtp_state->ts_current_line_db != 1 ||
3902 smtp_state->ts_db == NULL ||
3903 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3904 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3905 smtp_state->current_line != smtp_state->ts_db ||
3906 smtp_state->current_line_len != smtp_state->ts_db_len) {
3907 printf("smtp parser in inconsistent state\n");
3908 goto end;
3909 }
3910
cd3e32ce 3911 SCMutexLock(&f.m);
429c6388
AS
3912 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3913 request2, request2_len);
4a6908d3
AS
3914 if (r != 0) {
3915 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3916 SCMutexUnlock(&f.m);
4a6908d3
AS
3917 goto end;
3918 }
cd3e32ce 3919 SCMutexUnlock(&f.m);
4a6908d3
AS
3920 if (smtp_state->ts_current_line_db != 0 ||
3921 smtp_state->ts_db != NULL ||
3922 smtp_state->ts_db_len != 0 ||
3923 smtp_state->current_line == NULL ||
3924 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3925 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3926 printf("smtp parser in inconsistent state\n");
3927 goto end;
3928 }
3929
3930 result = 1;
3931end:
429c6388 3932 if (alp_tctx != NULL)
fdefb65b 3933 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
3934 StreamTcpFreeConfig(TRUE);
3935 FLOW_DESTROY(&f);
3936 return result;
3937}
3938
3939/*
3940 * \test Test retrieving lines when frag'ed.
3941 */
e43ce0a9 3942static int SMTPParserTest10(void)
4a6908d3
AS
3943{
3944 int result = 0;
3945 Flow f;
3946 int r = 0;
3947
3948 const char *request1_str = "";
3949 /* EHLO boo. */
3950 uint8_t request1_1[] = {
3951 0x0d,
3952 };
3953 int32_t request1_1_len = sizeof(request1_1);
3954
3955 /* com<CR><LF> */
3956 uint8_t request1_2[] = {
3957 0x0a,
3958 };
3959 int32_t request1_2_len = sizeof(request1_2);
3960
3961 const char *request2_str = "EHLO boo.com";
3962 /* EHLO boo.com<CR><LF> */
3963 uint8_t request2[] = {
3964 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3965 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3966 };
3967 int32_t request2_len = sizeof(request2);
3968
3969 TcpSession ssn;
8dbf7a0d 3970 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3971
3972 memset(&f, 0, sizeof(f));
3973 memset(&ssn, 0, sizeof(ssn));
3974
3975 FLOW_INITIALIZE(&f);
3976 f.protoctx = (void *)&ssn;
429c6388 3977 f.proto = IPPROTO_TCP;
4a6908d3
AS
3978
3979 StreamTcpInitConfig(TRUE);
e43ce0a9 3980 SMTPTestInitConfig();
4a6908d3 3981
cd3e32ce 3982 SCMutexLock(&f.m);
429c6388
AS
3983 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3984 request1_1, request1_1_len);
4a6908d3
AS
3985 if (r != 0) {
3986 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3987 SCMutexUnlock(&f.m);
4a6908d3
AS
3988 goto end;
3989 }
cd3e32ce 3990 SCMutexUnlock(&f.m);
bf24272c 3991 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3992 if (smtp_state == NULL) {
3993 printf("no smtp state: ");
3994 goto end;
3995 }
3996 if (smtp_state->current_line != NULL ||
3997 smtp_state->current_line_len != 0 ||
3998 smtp_state->ts_current_line_db != 1 ||
3999 smtp_state->ts_db == NULL ||
4000 smtp_state->ts_db_len != request1_1_len ||
4001 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
4002 printf("smtp parser in inconsistent state\n");
4003 goto end;
4004 }
4005
cd3e32ce 4006 SCMutexLock(&f.m);
429c6388
AS
4007 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4008 request1_2, request1_2_len);
4a6908d3
AS
4009 if (r != 0) {
4010 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 4011 SCMutexUnlock(&f.m);
4a6908d3
AS
4012 goto end;
4013 }
cd3e32ce 4014 SCMutexUnlock(&f.m);
4a6908d3
AS
4015 if (smtp_state->ts_current_line_db != 1 ||
4016 smtp_state->ts_db == NULL ||
4017 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
4018 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
4019 smtp_state->current_line != smtp_state->ts_db ||
4020 smtp_state->current_line_len != smtp_state->ts_db_len) {
4021 printf("smtp parser in inconsistent state\n");
4022 goto end;
4023 }
4024
cd3e32ce 4025 SCMutexLock(&f.m);
429c6388
AS
4026 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4027 request2, request2_len);
4a6908d3
AS
4028 if (r != 0) {
4029 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 4030 SCMutexUnlock(&f.m);
4a6908d3
AS
4031 goto end;
4032 }
cd3e32ce 4033 SCMutexUnlock(&f.m);
4a6908d3
AS
4034 if (smtp_state->ts_current_line_db != 0 ||
4035 smtp_state->ts_db != NULL ||
4036 smtp_state->ts_db_len != 0 ||
4037 smtp_state->current_line == NULL ||
4038 smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
4039 memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
4040 printf("smtp parser in inconsistent state\n");
4041 goto end;
4042 }
4043
4044 result = 1;
4045end:
429c6388 4046 if (alp_tctx != NULL)
fdefb65b 4047 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
4048 StreamTcpFreeConfig(TRUE);
4049 FLOW_DESTROY(&f);
4050 return result;
4051}
4052
4053/*
4054 * \test Test retrieving lines when frag'ed.
4055 */
e43ce0a9 4056static int SMTPParserTest11(void)
4a6908d3
AS
4057{
4058 int result = 0;
4059 Flow f;
4060 int r = 0;
4061
4062 const char *request1_str = "";
4063 /* EHLO boo. */
4064 uint8_t request1[] = {
4065 0x0a,
4066 };
4067 int32_t request1_len = sizeof(request1);
4068
4069 const char *request2_str = "EHLO boo.com";
4070 /* EHLO boo.com<CR><LF> */
4071 uint8_t request2[] = {
4072 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4073 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4074 };
4075 int32_t request2_len = sizeof(request2);
4076
4077 TcpSession ssn;
8dbf7a0d 4078 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
4079
4080 memset(&f, 0, sizeof(f));
4081 memset(&ssn, 0, sizeof(ssn));
4082
4083 FLOW_INITIALIZE(&f);
4084 f.protoctx = (void *)&ssn;
429c6388 4085 f.proto = IPPROTO_TCP;
4a6908d3
AS
4086
4087 StreamTcpInitConfig(TRUE);
e43ce0a9 4088 SMTPTestInitConfig();
4a6908d3 4089
cd3e32ce 4090 SCMutexLock(&f.m);
429c6388
AS
4091 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4092 request1, request1_len);
4a6908d3
AS
4093 if (r != 0) {
4094 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 4095 SCMutexUnlock(&f.m);
4a6908d3
AS
4096 goto end;
4097 }
cd3e32ce 4098 SCMutexUnlock(&f.m);
bf24272c 4099 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
4100 if (smtp_state == NULL) {
4101 printf("no smtp state: ");
4102 goto end;
4103 }
4104 if (smtp_state->current_line == NULL ||
4105 smtp_state->current_line_len != 0 ||
4106 smtp_state->ts_current_line_db == 1 ||
4107 smtp_state->ts_db != NULL ||
4108 smtp_state->ts_db_len != 0 ||
4109 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
4110 printf("smtp parser in inconsistent state\n");
4111 goto end;
4112 }
4113
cd3e32ce 4114 SCMutexLock(&f.m);
429c6388
AS
4115 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4116 request2, request2_len);
4a6908d3
AS
4117 if (r != 0) {
4118 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 4119 SCMutexUnlock(&f.m);
4a6908d3
AS
4120 goto end;
4121 }
cd3e32ce 4122 SCMutexUnlock(&f.m);
4a6908d3
AS
4123 if (smtp_state->ts_current_line_db != 0 ||
4124 smtp_state->ts_db != NULL ||
4125 smtp_state->ts_db_len != 0 ||
4126 smtp_state->current_line == NULL ||
4127 smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
4128 memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
4129 printf("smtp parser in inconsistent state\n");
4130 goto end;
4131 }
4132
4133 result = 1;
4134end:
429c6388 4135 if (alp_tctx != NULL)
fdefb65b 4136 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
4137 StreamTcpFreeConfig(TRUE);
4138 FLOW_DESTROY(&f);
4139 return result;
4140}
4141
e43ce0a9 4142static int SMTPParserTest12(void)
5311cd48
AS
4143{
4144 int result = 0;
4145 Signature *s = NULL;
4146 ThreadVars th_v;
4147 Packet *p = NULL;
4148 Flow f;
4149 TcpSession ssn;
4150 DetectEngineThreadCtx *det_ctx = NULL;
4151 DetectEngineCtx *de_ctx = NULL;
4152 SMTPState *smtp_state = NULL;
4153 int r = 0;
4154
4155 /* EHLO boo.com<CR><LF> */
4156 uint8_t request1[] = {
4157 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4158 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4159 };
4160 int32_t request1_len = sizeof(request1);
4161
4162 /* 388<CR><LF>
4163 */
4164 uint8_t reply1[] = {
4165 0x31, 0x38, 0x38, 0x0d, 0x0a,
4166 };
4167 uint32_t reply1_len = sizeof(reply1);
4168
8dbf7a0d 4169 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
429c6388 4170
5311cd48
AS
4171 memset(&th_v, 0, sizeof(th_v));
4172 memset(&f, 0, sizeof(f));
4173 memset(&ssn, 0, sizeof(ssn));
4174
4175 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
4176
4177 FLOW_INITIALIZE(&f);
4178 f.protoctx = (void *)&ssn;
429c6388 4179 f.proto = IPPROTO_TCP;
5311cd48
AS
4180 p->flow = &f;
4181 p->flowflags |= FLOW_PKT_TOSERVER;
4182 p->flowflags |= FLOW_PKT_ESTABLISHED;
4183 p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
4184 f.alproto = ALPROTO_SMTP;
4185
4186 StreamTcpInitConfig(TRUE);
e43ce0a9 4187 SMTPTestInitConfig();
5311cd48
AS
4188
4189 de_ctx = DetectEngineCtxInit();
4190 if (de_ctx == NULL)
4191 goto end;
4192
4193 de_ctx->flags |= DE_QUIET;
4194
4195 s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
4196 "(msg:\"SMTP event handling\"; "
7fa22e84 4197 "app-layer-event: smtp.invalid_reply; "
5311cd48
AS
4198 "sid:1;)");
4199 if (s == NULL)
4200 goto end;
4201
4202 SigGroupBuild(de_ctx);
4203 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4204
cd3e32ce 4205 SCMutexLock(&f.m);
429c6388
AS
4206 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START,
4207 request1, request1_len);
5311cd48
AS
4208 if (r != 0) {
4209 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 4210 SCMutexUnlock(&f.m);
5311cd48
AS
4211 goto end;
4212 }
cd3e32ce 4213 SCMutexUnlock(&f.m);
5311cd48
AS
4214
4215 smtp_state = f.alstate;
4216 if (smtp_state == NULL) {
4217 printf("no smtp state: ");
4218 goto end;
4219 }
4220
4221 /* do detect */
4222 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4223
4224 if (PacketAlertCheck(p, 1)) {
4225 printf("sid 1 matched. It shouldn't match: ");
4226 goto end;
4227 }
4228
cd3e32ce 4229 SCMutexLock(&f.m);
429c6388
AS
4230 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT | STREAM_TOCLIENT,
4231 reply1, reply1_len);
5311cd48
AS
4232 if (r == 0) {
4233 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 4234 SCMutexUnlock(&f.m);
5311cd48
AS
4235 goto end;
4236 }
cd3e32ce 4237 SCMutexUnlock(&f.m);
5311cd48
AS
4238
4239 /* do detect */
4240 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4241
4242 if (!PacketAlertCheck(p, 1)) {
4243 printf("sid 1 didn't match. Should have matched: ");
4244 goto end;
4245 }
4246
4247 result = 1;
4248
4249end:
4250 SigGroupCleanup(de_ctx);
4251 SigCleanSignatures(de_ctx);
4252
4253 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4254 DetectEngineCtxFree(de_ctx);
4255
429c6388 4256 if (alp_tctx != NULL)
fdefb65b 4257 AppLayerParserThreadCtxFree(alp_tctx);
5311cd48 4258 StreamTcpFreeConfig(TRUE);
5311cd48
AS
4259 FLOW_DESTROY(&f);
4260 UTHFreePackets(&p, 1);
4261 return result;
4262}
4263
e43ce0a9 4264static int SMTPParserTest13(void)
5311cd48
AS
4265{
4266 int result = 0;
4267 Signature *s = NULL;
4268 ThreadVars th_v;
4269 Packet *p = NULL;
4270 Flow f;
4271 TcpSession ssn;
4272 DetectEngineThreadCtx *det_ctx = NULL;
4273 DetectEngineCtx *de_ctx = NULL;
4274 SMTPState *smtp_state = NULL;
4275 int r = 0;
4276
4277 /* EHLO boo.com<CR><LF> */
4278 uint8_t request1[] = {
4279 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4280 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4281 };
4282 int32_t request1_len = sizeof(request1);
4283
4284 /* 250<CR><LF>
4285 */
4286 uint8_t reply1[] = {
4287 0x32, 0x35, 0x30, 0x0d, 0x0a,
4288 };
4289 uint32_t reply1_len = sizeof(reply1);
4290
4291 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
4292 * RCPT TO:pbsf@asdfs.com<CR><LF>
4293 * DATA<CR><LF>
4294 * STARTTLS<CR><LF>
4295 */
4296 uint8_t request2[] = {
4297 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4298 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4299 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4300 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
4301 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4302 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4303 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
4304 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
4305 0x0d, 0x0a
4306 };
4307 uint32_t request2_len = sizeof(request2);
4308
8dbf7a0d 4309 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
429c6388 4310
5311cd48
AS
4311 memset(&th_v, 0, sizeof(th_v));
4312 memset(&f, 0, sizeof(f));
4313 memset(&ssn, 0, sizeof(ssn));
4314
4315 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
4316
4317 FLOW_INITIALIZE(&f);
4318 f.protoctx = (void *)&ssn;
429c6388 4319 f.proto = IPPROTO_TCP;
5311cd48
AS
4320 p->flow = &f;
4321 p->flowflags |= FLOW_PKT_TOSERVER;
4322 p->flowflags |= FLOW_PKT_ESTABLISHED;
4323 p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
4324 f.alproto = ALPROTO_SMTP;
4325
4326 StreamTcpInitConfig(TRUE);
e43ce0a9 4327 SMTPTestInitConfig();
5311cd48
AS
4328
4329 de_ctx = DetectEngineCtxInit();
4330 if (de_ctx == NULL)
4331 goto end;
4332
4333 de_ctx->flags |= DE_QUIET;
4334
4335 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
4336 "(msg:\"SMTP event handling\"; "
7fa22e84 4337 "app-layer-event: "
5311cd48
AS
4338 "smtp.invalid_pipelined_sequence; "
4339 "sid:1;)");
4340 if (s == NULL)
4341 goto end;
4342
4343 SigGroupBuild(de_ctx);
4344 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4345
cd3e32ce 4346 SCMutexLock(&f.m);
429c6388
AS
4347 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START,
4348 request1, request1_len);
5311cd48
AS
4349 if (r != 0) {
4350 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 4351 SCMutexUnlock(&f.m);
5311cd48
AS
4352 goto end;
4353 }
cd3e32ce 4354 SCMutexUnlock(&f.m);
5311cd48
AS
4355
4356 smtp_state = f.alstate;
4357 if (smtp_state == NULL) {
4358 printf("no smtp state: ");
4359 goto end;
4360 }
4361
4362 /* do detect */
4363 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4364
4365 if (PacketAlertCheck(p, 1)) {
4366 printf("sid 1 matched. It shouldn't match: ");
4367 goto end;
4368 }
4369
cd3e32ce 4370 SCMutexLock(&f.m);
429c6388
AS
4371 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
4372 reply1, reply1_len);
5311cd48
AS
4373 if (r != 0) {
4374 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 4375 SCMutexUnlock(&f.m);
5311cd48
AS
4376 goto end;
4377 }
cd3e32ce 4378 SCMutexUnlock(&f.m);
5311cd48
AS
4379
4380 /* do detect */
4381 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4382
4383 if (PacketAlertCheck(p, 1)) {
4384 printf("sid 1 matched. It shouldn't match: ");
4385 goto end;
4386 }
4387
cd3e32ce 4388 SCMutexLock(&f.m);
429c6388
AS
4389 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4390 request2, request2_len);
5311cd48
AS
4391 if (r != 0) {
4392 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 4393 SCMutexUnlock(&f.m);
5311cd48
AS
4394 goto end;
4395 }
cd3e32ce 4396 SCMutexUnlock(&f.m);
5311cd48
AS
4397
4398 /* do detect */
4399 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4400
4401 if (!PacketAlertCheck(p, 1)) {
4402 printf("sid 1 didn't match. Should have matched: ");
4403 goto end;
4404 }
4405
4406 result = 1;
4407
4408end:
4409 SigGroupCleanup(de_ctx);
4410 SigCleanSignatures(de_ctx);
4411
4412 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4413 DetectEngineCtxFree(de_ctx);
4414
429c6388 4415 if (alp_tctx != NULL)
fdefb65b 4416 AppLayerParserThreadCtxFree(alp_tctx);
5311cd48 4417 StreamTcpFreeConfig(TRUE);
5311cd48
AS
4418 FLOW_DESTROY(&f);
4419 UTHFreePackets(&p, 1);
4420 return result;
4421}
4422
c2dc6867
DA
4423/**
4424 * \test Test DATA command w/MIME message.
4425 */
e43ce0a9 4426static int SMTPParserTest14(void)
c2dc6867
DA
4427{
4428 int result = 0;
4429 Flow f;
4430 int r = 0;
4431
4432 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
6467a5d5 4433 static uint8_t welcome_reply[] = {
c2dc6867
DA
4434 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
4435 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
4436 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
4437 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
4438 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
4439 0x0d, 0x0a
4440 };
6467a5d5 4441 static uint32_t welcome_reply_len = sizeof(welcome_reply);
c2dc6867
DA
4442
4443 /* EHLO boo.com<CR><LF> */
6467a5d5 4444 static uint8_t request1[] = {
c2dc6867
DA
4445 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4446 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
4447 };
6467a5d5 4448 static uint32_t request1_len = sizeof(request1);
c2dc6867
DA
4449 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
4450 * 250-SIZE 35882577<CR><LF>
4451 * 250-8BITMIME<CR><LF>
4452 * 250-STARTTLS<CR><LF>
4453 * 250 ENHANCEDSTATUSCODES<CR><LF>
4454 */
6467a5d5 4455 static uint8_t reply1[] = {
c2dc6867
DA
4456 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
4457 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
4458 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
4459 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
4460 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
4461 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
4462 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
4463 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
4464 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
4465 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
4466 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
4467 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
4468 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
4469 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
4470 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
4471 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
4472 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
4473 };
6467a5d5 4474 static uint32_t reply1_len = sizeof(reply1);
c2dc6867
DA
4475
4476 /* MAIL FROM:asdff@asdf.com<CR><LF> */
6467a5d5 4477 static uint8_t request2[] = {
c2dc6867
DA
4478 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4479 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
4480 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
4481 0x0d, 0x0a
4482 };
6467a5d5 4483 static uint32_t request2_len = sizeof(request2);
c2dc6867 4484 /* 250 2.1.0 Ok<CR><LF> */
6467a5d5 4485 static uint8_t reply2[] = {
c2dc6867
DA
4486 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4487 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4488 };
6467a5d5 4489 static uint32_t reply2_len = sizeof(reply2);
c2dc6867
DA
4490
4491 /* RCPT TO:bimbs@gmail.com<CR><LF> */
6467a5d5 4492 static uint8_t request3[] = {
c2dc6867
DA
4493 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
4494 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
4495 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
4496 0x0a
4497 };
6467a5d5 4498 static uint32_t request3_len = sizeof(request3);
c2dc6867 4499 /* 250 2.1.5 Ok<CR><LF> */
6467a5d5 4500 static uint8_t reply3[] = {
c2dc6867
DA
4501 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4502 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4503 };
6467a5d5 4504 static uint32_t reply3_len = sizeof(reply3);
c2dc6867
DA
4505
4506 /* DATA<CR><LF> */
6467a5d5 4507 static uint8_t request4[] = {
c2dc6867
DA
4508 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
4509 };
6467a5d5 4510 static uint32_t request4_len = sizeof(request4);
c2dc6867 4511 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
6467a5d5 4512 static uint8_t reply4[] = {
c2dc6867
DA
4513 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
4514 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
4515 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
4516 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
4517 0x4c, 0x46, 0x3e, 0x0d, 0x0a
4518 };
6467a5d5 4519 static uint32_t reply4_len = sizeof(reply4);
c2dc6867
DA
4520
4521 /* MIME_MSG */
6467a5d5
TD
4522 static uint64_t filesize = 133;
4523 static uint8_t request4_msg[] = {
c2dc6867
DA
4524 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4525 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4526 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4527 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4528 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4529 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4530 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4531 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4532 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4533 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4534 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4535 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4536 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4537 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4538 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4539 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4540 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4541 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4542 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4543 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4544 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4545 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4546 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4547 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4548 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4549 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4550 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4551 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4552 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4553 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4554 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4555 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4556 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4557 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4558 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4559 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4560 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4561 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4562 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4563 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4564 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4565 0x41, 0x3D, 0x3D, 0x0D,0x0A };
6467a5d5 4566 static uint32_t request4_msg_len = sizeof(request4_msg);
c2dc6867
DA
4567
4568 /* DATA COMPLETED */
6467a5d5 4569 static uint8_t request4_end[] = {
c2dc6867
DA
4570 0x0d, 0x0a, 0x2e, 0x0d, 0x0a
4571 };
6467a5d5 4572 static uint32_t request4_end_len = sizeof(request4_end);
c2dc6867 4573 /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
6467a5d5 4574 static uint8_t reply4_end[] = {
c2dc6867
DA
4575 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4576 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
4577 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
4578 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
4579 0x46, 0x32, 0x0d, 0x0a
4580 };
6467a5d5 4581 static uint32_t reply4_end_len = sizeof(reply4_end);
c2dc6867
DA
4582
4583 /* QUIT<CR><LF> */
6467a5d5 4584 static uint8_t request5[] = {
c2dc6867
DA
4585 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
4586 };
6467a5d5 4587 static uint32_t request5_len = sizeof(request5);
c2dc6867 4588 /* 221 2.0.0 Bye<CR><LF> */
6467a5d5 4589 static uint8_t reply5[] = {
c2dc6867
DA
4590 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4591 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
4592 };
6467a5d5 4593 static uint32_t reply5_len = sizeof(reply5);
c2dc6867
DA
4594
4595 TcpSession ssn;
260872cc 4596 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
c2dc6867
DA
4597
4598 memset(&f, 0, sizeof(f));
4599 memset(&ssn, 0, sizeof(ssn));
4600
4601 FLOW_INITIALIZE(&f);
4602 f.protoctx = (void *)&ssn;
260872cc 4603 f.proto = IPPROTO_TCP;
c2dc6867
DA
4604
4605 StreamTcpInitConfig(TRUE);
e43ce0a9 4606 SMTPTestInitConfig();
c2dc6867 4607
260872cc
EL
4608 SCMutexLock(&f.m);
4609 /* Welcome reply */
4610 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
4611 welcome_reply, welcome_reply_len);
c2dc6867
DA
4612 if (r != 0) {
4613 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4614 SCMutexUnlock(&f.m);
c2dc6867
DA
4615 goto end;
4616 }
260872cc 4617 SCMutexUnlock(&f.m);
c2dc6867
DA
4618 SMTPState *smtp_state = f.alstate;
4619 if (smtp_state == NULL) {
4620 printf("no smtp state: ");
4621 goto end;
4622 }
4623 if (smtp_state->input_len != 0 ||
260872cc 4624 smtp_state->cmds_cnt != 0 ||
c2dc6867 4625 smtp_state->cmds_idx != 0 ||
260872cc
EL
4626 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
4627 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4628 goto end;
4629 }
4630
260872cc
EL
4631 SCMutexLock(&f.m);
4632 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4633 request1, request1_len);
c2dc6867
DA
4634 if (r != 0) {
4635 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4636 SCMutexUnlock(&f.m);
c2dc6867
DA
4637 goto end;
4638 }
260872cc 4639 SCMutexUnlock(&f.m);
c2dc6867
DA
4640 if (smtp_state->input_len != 0 ||
4641 smtp_state->cmds_cnt != 1 ||
4642 smtp_state->cmds_idx != 0 ||
4643 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4644 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4645 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4646 goto end;
4647 }
4648
260872cc 4649 SCMutexLock(&f.m);
c2dc6867 4650 /* EHLO Reply */
260872cc 4651 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4652 reply1, reply1_len);
4653 if (r != 0) {
4654 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4655 SCMutexUnlock(&f.m);
c2dc6867
DA
4656 goto end;
4657 }
534360fc
EL
4658
4659 if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) {
4660 printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len);
4661 SCMutexUnlock(&f.m);
4662 goto end;
4663 }
4664
260872cc 4665 SCMutexUnlock(&f.m);
c2dc6867
DA
4666 if (smtp_state->input_len != 0 ||
4667 smtp_state->cmds_cnt != 0 ||
4668 smtp_state->cmds_idx != 0 ||
4669 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4670 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4671 goto end;
4672 }
4673
260872cc 4674 SCMutexLock(&f.m);
c2dc6867 4675 /* MAIL FROM Request */
260872cc 4676 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4677 request2, request2_len);
4678 if (r != 0) {
4679 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4680 SCMutexUnlock(&f.m);
c2dc6867
DA
4681 goto end;
4682 }
260872cc 4683 SCMutexUnlock(&f.m);
c2dc6867
DA
4684 if (smtp_state->input_len != 0 ||
4685 smtp_state->cmds_cnt != 1 ||
4686 smtp_state->cmds_idx != 0 ||
4687 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4688 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4689 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4690 goto end;
4691 }
4692
260872cc 4693 SCMutexLock(&f.m);
c2dc6867 4694 /* MAIL FROM Reply */
260872cc 4695 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4696 reply2, reply2_len);
4697 if (r != 0) {
4698 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4699 SCMutexUnlock(&f.m);
c2dc6867
DA
4700 goto end;
4701 }
fbd6428f
EL
4702
4703 if ((smtp_state->curr_tx->mail_from_len != 14) ||
4704 strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) {
4705 printf("incorrect parsing of MAIL FROM field '%s' (%d)\n",
4706 smtp_state->curr_tx->mail_from,
4707 smtp_state->curr_tx->mail_from_len);
4708 SCMutexUnlock(&f.m);
4709 goto end;
4710 }
4711
260872cc 4712 SCMutexUnlock(&f.m);
c2dc6867
DA
4713 if (smtp_state->input_len != 0 ||
4714 smtp_state->cmds_cnt != 0 ||
4715 smtp_state->cmds_idx != 0 ||
4716 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4717 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4718 goto end;
4719 }
4720
260872cc 4721 SCMutexLock(&f.m);
c2dc6867 4722 /* RCPT TO Request */
260872cc 4723 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4724 request3, request3_len);
4725 if (r != 0) {
4726 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4727 SCMutexUnlock(&f.m);
c2dc6867
DA
4728 goto end;
4729 }
260872cc 4730 SCMutexUnlock(&f.m);
c2dc6867
DA
4731 if (smtp_state->input_len != 0 ||
4732 smtp_state->cmds_cnt != 1 ||
4733 smtp_state->cmds_idx != 0 ||
4734 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4735 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4736 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4737 goto end;
4738 }
4739
260872cc 4740 SCMutexLock(&f.m);
c2dc6867 4741 /* RCPT TO Reply */
260872cc 4742 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4743 reply3, reply3_len);
4744 if (r != 0) {
4745 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4746 SCMutexUnlock(&f.m);
c2dc6867
DA
4747 goto end;
4748 }
260872cc 4749 SCMutexUnlock(&f.m);
c2dc6867
DA
4750 if (smtp_state->input_len != 0 ||
4751 smtp_state->cmds_cnt != 0 ||
4752 smtp_state->cmds_idx != 0 ||
4753 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4754 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4755 goto end;
4756 }
4757
4758 /* Enable mime decoding */
4759 smtp_config.decode_mime = 1;
4760 smtp_config.mime_config.decode_base64 = 1;
4761 smtp_config.mime_config.decode_quoted_printable = 1;
4762 MimeDecSetConfig(&smtp_config.mime_config);
4763
260872cc 4764 SCMutexLock(&f.m);
c2dc6867 4765 /* DATA request */
260872cc 4766 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4767 request4, request4_len);
4768 if (r != 0) {
4769 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4770 SCMutexUnlock(&f.m);
c2dc6867
DA
4771 goto end;
4772 }
260872cc 4773 SCMutexUnlock(&f.m);
c2dc6867
DA
4774
4775 if (smtp_state->input_len != 0 ||
4776 smtp_state->cmds_cnt != 1 ||
4777 smtp_state->cmds_idx != 0 ||
4778 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
4779 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4780 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4781 goto end;
4782 }
4783
260872cc 4784 SCMutexLock(&f.m);
c2dc6867 4785 /* Data reply */
260872cc 4786 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4787 reply4, reply4_len);
4788 if (r != 0) {
4789 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4790 SCMutexUnlock(&f.m);
c2dc6867
DA
4791 goto end;
4792 }
260872cc 4793 SCMutexUnlock(&f.m);
c2dc6867
DA
4794 if (smtp_state->input_len != 0 ||
4795 smtp_state->cmds_cnt != 0 ||
4796 smtp_state->cmds_idx != 0 ||
4797 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
4798 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
260872cc 4799 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4800 goto end;
4801 }
4802
260872cc 4803 SCMutexLock(&f.m);
c2dc6867 4804 /* DATA message */
260872cc 4805 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4806 request4_msg, request4_msg_len);
4807 if (r != 0) {
4808 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4809 SCMutexUnlock(&f.m);
c2dc6867
DA
4810 goto end;
4811 }
260872cc 4812 SCMutexUnlock(&f.m);
c2dc6867
DA
4813
4814 if (smtp_state->input_len != 0 ||
4815 smtp_state->cmds_cnt != 0 ||
4816 smtp_state->cmds_idx != 0 ||
56b74c8b 4817 smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
c2dc6867
DA
4818 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
4819 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
260872cc 4820 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4821 goto end;
4822 }
4823
260872cc 4824 SCMutexLock(&f.m);
c2dc6867 4825 /* DATA . request */
260872cc 4826 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4827 request4_end, request4_end_len);
4828 if (r != 0) {
4829 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4830 SCMutexUnlock(&f.m);
c2dc6867
DA
4831 goto end;
4832 }
260872cc 4833 SCMutexUnlock(&f.m);
c2dc6867
DA
4834
4835 if (smtp_state->input_len != 0 ||
4836 smtp_state->cmds_cnt != 1 ||
4837 smtp_state->cmds_idx != 0 ||
4838 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
56b74c8b 4839 smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
c2dc6867 4840 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4841 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4842 goto end;
4843 }
4844
4845 SMTPState *state = (SMTPState *) f.alstate;
4846 FileContainer *files = state->files_ts;
4847 if (files != NULL && files->head != NULL) {
4848 File *file = files->head;
4849
4850 if(strncmp((const char *)file->name, "test.exe", 8) != 0){
4851 printf("smtp-mime file name is incorrect");
4852 goto end;
4853 }
e43ce0a9
VJ
4854 if (FileSize(file) != filesize){
4855 printf("smtp-mime file size %"PRIu64" is incorrect", FileSize(file));
c2dc6867
DA
4856 goto end;
4857 }
6467a5d5
TD
4858 static uint8_t org_binary[] = {
4859 0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
c2dc6867
DA
4860 0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
4861 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4862 0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
4863 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
4864 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4865 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4866 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
4867 0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
4868 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4869 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
4870 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4871 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4872 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4873 0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
4874 0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
4875 0x5C, 0x7A, 0x00, 0x00, 0x38,};
e43ce0a9
VJ
4876
4877 if (StreamingBufferCompareRawData(file->sb,
4878 org_binary, sizeof(org_binary)) != 1)
4879 {
4880 printf("smtp-mime file data incorrect\n");
4881 goto end;
c2dc6867
DA
4882 }
4883 }
4884
260872cc 4885 SCMutexLock(&f.m);
c2dc6867 4886 /* DATA . reply */
260872cc 4887 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4888 reply4_end, reply4_end_len);
4889 if (r != 0) {
4890 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4891 SCMutexUnlock(&f.m);
c2dc6867
DA
4892 goto end;
4893 }
260872cc 4894 SCMutexUnlock(&f.m);
c2dc6867
DA
4895 if (smtp_state->input_len != 0 ||
4896 smtp_state->cmds_cnt != 0 ||
4897 smtp_state->cmds_idx != 0 ||
4898 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4899 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4900 goto end;
4901 }
4902
260872cc 4903 SCMutexLock(&f.m);
c2dc6867 4904 /* QUIT Request */
260872cc 4905 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4906 request5, request5_len);
4907 if (r != 0) {
4908 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4909 SCMutexUnlock(&f.m);
c2dc6867
DA
4910 goto end;
4911 }
260872cc 4912 SCMutexUnlock(&f.m);
c2dc6867
DA
4913 if (smtp_state->input_len != 0 ||
4914 smtp_state->cmds_cnt != 1 ||
4915 smtp_state->cmds_idx != 0 ||
4916 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4917 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4918 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4919 goto end;
4920 }
4921
260872cc 4922 SCMutexLock(&f.m);
c2dc6867 4923 /* QUIT Reply */
260872cc 4924 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4925 reply5, reply5_len);
4926 if (r != 0) {
4927 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4928 SCMutexUnlock(&f.m);
c2dc6867
DA
4929 goto end;
4930 }
260872cc 4931 SCMutexUnlock(&f.m);
c2dc6867
DA
4932 if (smtp_state->input_len != 0 ||
4933 smtp_state->cmds_cnt != 0 ||
4934 smtp_state->cmds_idx != 0 ||
4935 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4936 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4937 goto end;
4938 }
4939
4940 result = 1;
260872cc
EL
4941end:
4942 if (alp_tctx != NULL)
4943 AppLayerParserThreadCtxFree(alp_tctx);
c2dc6867
DA
4944 StreamTcpFreeConfig(TRUE);
4945 FLOW_DESTROY(&f);
c2dc6867
DA
4946 return result;
4947}
4948
e43ce0a9 4949static int SMTPProcessDataChunkTest01(void){
c2dc6867
DA
4950 Flow f;
4951 FLOW_INITIALIZE(&f);
4952 f.flags = FLOW_FILE_NO_STORE_TS;
4953 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4954 int ret;
d2657bec 4955 ret = SMTPProcessDataChunk(NULL, 0, state);
c2dc6867 4956
52983bf3 4957 return ret == 0;
c2dc6867
DA
4958}
4959
4960
e43ce0a9 4961static int SMTPProcessDataChunkTest02(void){
c2dc6867
DA
4962 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4963 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4964 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4965 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4966 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4967 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4968 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4969 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4970 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4971 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4972 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4973 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4974 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4975 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4976 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4977 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4978 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4979 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4980 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4981 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4982 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4983 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4984 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4985 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4986 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4987 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4988 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4989 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4990 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4991 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4992 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4993 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4994 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4995 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4996 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4997 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4998 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4999 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5000 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
5001 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
5002 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
5003 0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
5004
5005 Flow f;
5006 FLOW_INITIALIZE(&f);
5007 f.alstate = SMTPStateAlloc();
5008 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5009 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5010 state->body_begin = 1;
5011 int ret;
d2657bec 5012 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
c2dc6867 5013
52983bf3 5014 return ret == 0;
c2dc6867
DA
5015}
5016
5017
5018
e43ce0a9 5019static int SMTPProcessDataChunkTest03(void){
c2dc6867
DA
5020 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
5021 char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
5022 char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5023 char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
5024 char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
5025 char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
5026 char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
5027 char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5028 char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
5029 char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
5030 char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
5031 char mimemsg12[] = {0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, };
5032
5033 Flow f;
5034 FLOW_INITIALIZE(&f);
5035 f.alstate = SMTPStateAlloc();
5036 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5037 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5038 int ret;
5039
5040 state->body_begin = 1;
d2657bec 5041 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
c2dc6867
DA
5042 if(ret) goto end;
5043 state->body_begin = 0;
d2657bec 5044 ret = SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state);
c2dc6867 5045 if(ret) goto end;
d2657bec 5046 ret = SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state);
c2dc6867 5047 if(ret) goto end;
d2657bec 5048 ret = SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state);
c2dc6867 5049 if(ret) goto end;
d2657bec 5050 ret = SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state);
c2dc6867 5051 if(ret) goto end;
d2657bec 5052 ret = SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state);
c2dc6867 5053 if(ret) goto end;
d2657bec 5054 ret = SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state);
c2dc6867 5055 if(ret) goto end;
d2657bec 5056 ret = SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state);
c2dc6867 5057 if(ret) goto end;
d2657bec 5058 ret = SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state);
c2dc6867 5059 if(ret) goto end;
d2657bec 5060 ret = SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state);
c2dc6867 5061 if(ret) goto end;
d2657bec 5062 ret = SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state);
c2dc6867
DA
5063 if(ret) goto end;
5064 state->body_end = 1;
d2657bec 5065 ret = SMTPProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state);
c2dc6867
DA
5066 if(ret) goto end;
5067
5068 end:
52983bf3 5069 return ret == 0;
c2dc6867
DA
5070}
5071
5072
e43ce0a9 5073static int SMTPProcessDataChunkTest04(void){
c2dc6867
DA
5074 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
5075 char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
5076 char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5077 char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
5078 char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
5079 char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
5080 char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
5081 char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5082 char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
5083 char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
5084 char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
5085
5086 Flow f;
5087 FLOW_INITIALIZE(&f);
5088 f.alstate = SMTPStateAlloc();
5089 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5090 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5091 int ret = MIME_DEC_OK;
5092
5093 state->body_begin = 1;
d2657bec
GL
5094 if(SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end;
5095 if(SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end;
5096 if(SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end;
5097 if(SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end;
5098 if(SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end;
5099 if(SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end;
5100 if(SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end;
c2dc6867
DA
5101 state->body_begin = 0;
5102 state->body_end = 1;
d2657bec 5103 if(SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end;
c2dc6867 5104 state->body_end = 0;
d2657bec
GL
5105 if(SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end;
5106 if(SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end;
5107 if(SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end;
c2dc6867
DA
5108
5109 end:
52983bf3 5110 return ret == 0;
c2dc6867
DA
5111}
5112
e43ce0a9 5113static int SMTPProcessDataChunkTest05(void){
c2dc6867
DA
5114 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
5115 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
5116 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
5117 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
5118 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
5119 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
5120 0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
5121
5122 Flow f;
7f700a13 5123 int ret;
c2dc6867
DA
5124 FLOW_INITIALIZE(&f);
5125 f.alstate = SMTPStateAlloc();
7f700a13 5126 FAIL_IF(f.alstate == NULL);
c2dc6867
DA
5127 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5128 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
7f700a13 5129 FAIL_IF(state == NULL);
c2dc6867 5130 state->body_begin = 1;
d2657bec 5131 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
7f700a13 5132 FAIL_IF(ret != 0);
c2dc6867 5133 state->body_begin = 0;
c2dc6867
DA
5134 SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate;
5135 FileContainer *files = smtp_state->files_ts;
7f700a13 5136 FAIL_IF(files == NULL);
c2dc6867 5137 File *file = files->head;
7f700a13 5138 FAIL_IF(file == NULL);
d2657bec 5139 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
7f700a13 5140 FAIL_IF(ret != 0);
e43ce0a9 5141 FAIL_IF((uint32_t)FileSize(file) != 106);
7f700a13
VJ
5142 SMTPStateFree(smtp_state);
5143 FLOW_DESTROY(&f);
5144 PASS;
c2dc6867
DA
5145}
5146
87599bc7
AS
5147#endif /* UNITTESTS */
5148
576ec7da
AS
5149void SMTPParserRegisterTests(void)
5150{
87599bc7 5151#ifdef UNITTESTS
796dd522
JI
5152 UtRegisterTest("SMTPParserTest01", SMTPParserTest01);
5153 UtRegisterTest("SMTPParserTest02", SMTPParserTest02);
5154 UtRegisterTest("SMTPParserTest03", SMTPParserTest03);
5155 UtRegisterTest("SMTPParserTest04", SMTPParserTest04);
5156 UtRegisterTest("SMTPParserTest05", SMTPParserTest05);
5157 UtRegisterTest("SMTPParserTest06", SMTPParserTest06);
5158 UtRegisterTest("SMTPParserTest07", SMTPParserTest07);
5159 UtRegisterTest("SMTPParserTest08", SMTPParserTest08);
5160 UtRegisterTest("SMTPParserTest09", SMTPParserTest09);
5161 UtRegisterTest("SMTPParserTest10", SMTPParserTest10);
5162 UtRegisterTest("SMTPParserTest11", SMTPParserTest11);
5163 UtRegisterTest("SMTPParserTest12", SMTPParserTest12);
5164 UtRegisterTest("SMTPParserTest13", SMTPParserTest13);
5165 UtRegisterTest("SMTPParserTest14", SMTPParserTest14);
5166 UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01);
5167 UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02);
5168 UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03);
5169 UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04);
5170 UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05);
87599bc7 5171#endif /* UNITTESTS */
4a6908d3 5172
576ec7da
AS
5173 return;
5174}