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